Java Forum / General / September 2007
dependency-detection in java
Andreas Leitgeb - 30 Aug 2007 21:38 GMT Say, I've got two classes A and B, one of which (A) contains "static final" fields, the other (B) references these fields. Now the compiler doesn't use references, but includes the values from A directly in B.
Now suppose some of these fields in A are changed.
What is the usual "trick" to make sure that all "B"-type classes are recompiled, when an "A"-type class has changed?
Is the only sensible way really to remove *all* .class files and have *all* files recompiled, or does there exist some trick to let the compiler know these dependencies, and do the right thing?
Seemingly, it didn't do it last time I had to change such an "A"-type class.
Does there perhaps exist a thirdparty-tool, (a la makedepends & make for C++) that makes sure that really all neccessary recompilations are performed?
As it seems, the class-file for "B" doesn't even have any mention of "A" (unless it also uses other fields or methods of A, of course).
As a programmer I'd rather not have to think about manually removing .class-files that are no longer up-to-date.
PS: I'm bound to still work with java 1.4, but if such a feature exists for newer versions, I'd still also like to know.
Lew - 30 Aug 2007 21:44 GMT > Say, I've got two classes A and B, one of which (A) > contains "static final" fields, the other (B) [quoted text clipped - 7 lines] > "B"-type classes are recompiled, when an "A"-type > class has changed? Compile B, which will cause it to compile A.
> Is the only sensible way really to remove *all* > ..class files and have *all* files recompiled, or > does there exist some trick to let the compiler > know these dependencies, and do the right thing? Yes.
> Seemingly, it didn't do it last time I had to > change such an "A"-type class. Because you compiled A, not B.
> Does there perhaps exist a thirdparty-tool, (a la > makedepends & make for C++) that makes sure that > really all neccessary recompilations are performed? "javac".
> As it seems, the class-file for "B" doesn't even > have any mention of "A" (unless it also uses other > fields or methods of A, of course). But the source file does.
> As a programmer I'd rather not have to think about > manually removing .class-files that are no longer > up-to-date. Ant.
> PS: I'm bound to still work with java 1.4, but if > such a feature exists for newer versions, I'd > still also like to know. Use Ant.
 Signature Lew
Andreas Leitgeb - 30 Aug 2007 22:46 GMT >> Say, I've got two classes A and B, one of which (A) >> contains "static final" fields, the other (B) [quoted text clipped - 5 lines] >> "B"-type classes are recompiled, when an "A"-type >> class has changed?
> Compile B, which will cause it to compile A. That's not the point. Actually, I don't really know which classes do reference some A's static final fields (there are usually a couple of such type "B" classes for each type "A" class).
The only thing I see is, that some .java-file, of which I don't necessarily know that it happens to be of type A (that is: contains static final constants) has been changed (e.g. in some version control system), and I want to be sure that after next "build" the whole project is correctly (but not unneccessarily) recompiled.
Is this really such an absurd wish in the world of java?
>> Does there perhaps exist a thirdparty-tool, (a la >> makedepends & make for C++) that makes sure that >> really all neccessary recompilations are performed? > "javac". > Ant. The combination of these two makes it not work. As it seems, ant only passes those .java files to the compiler that are newer than their .class files (or whose .class-file doesn't exist), which means it passes only A.java, but not B.java to the compiler in the given szenario.
If ant were able to know B's dependency on A, and pass B.java to the compiler as well, my problem would be solved.
What one needs is some dependency-information generated by javac when first compiling B.java (of course it would generate that for all classes, but only for type B classes it would be non-empty). Actually that would have to be exactly the list of other classes, of which static finals were used.
With this information, ant could make a better guess at what filenames to pass to the compiler.
Stefan Ram - 30 Aug 2007 21:52 GMT >What is the usual "trick" to make sure that all >"B"-type classes are recompiled, when an "A"-type >class has changed? It is assumed that constants do not change.
A change to correct a mistake should happen rarely and might trigger a manual deletion of all class files.
If the value might change in time, it might be better read from a configuration file than be hard-coded in the source code.
As a work-around, a getter-method might be used.
Andreas Leitgeb - 30 Aug 2007 22:51 GMT >>What is the usual "trick" to make sure that all >>"B"-type classes are recompiled, when an "A"-type >>class has changed?
> It is assumed that constants do not change. > A change to correct a mistake should happen > rarely and might trigger a manual deletion of > all class files. Changes happen. :-/ There can be various reasons for why constants change "just this time"...
In my case it were strings defined in an .idl file.
> If the value might change in time, it might > be better read from a configuration file than > be hard-coded in the source code. It's supposed to be const, but casually, such things just do change. The customer wants it that other way...
Daniel Pitts - 31 Aug 2007 00:39 GMT > >>What is the usual "trick" to make sure that all > >>"B"-type classes are recompiled, when an "A"-type [quoted text clipped - 16 lines] > things just do change. The customer wants it > that other way... Generally, if the user wants a constant "that other way", then you do externalize it into a configuration file.
In any case, I suggest using "ant" (google it). It helps manage builds and build-related tasks.
Andreas Leitgeb - 31 Aug 2007 07:37 GMT > Generally, if the user wants a constant "that other way", then you do > externalize it into a configuration file. Ok, I put it another way: The constant may change a couple of times during development+testing-phase, but will not change in the future. If it weren't ever to change, I would have inlined the value at each place where it is used, directly.
One can think of it that it actually *is* in a separate configuration file, which happens to be in the format of java-source (actually, it's in an idl-file, from which the java-file is generated)...
> In any case, I suggest using "ant" (google it). It helps manage builds > and build-related tasks. Actually, we *use* ant, and as it is now, "ant" is part of the problem. because it only feeds the changed classes to the compiler, but not the dependent ones.
Bent C Dalager - 31 Aug 2007 10:10 GMT >Actually, we *use* ant, and as it is now, "ant" is part of the problem. >because it only feeds the changed classes to the compiler, but not the >dependent ones. As far as I can recall:
- final statics are inlined in client classes without any reference to where they came from and so changes to the class that defines them will not cause client classes to be recompiled.
- javac doesn't handle this at all and so fails to correctly recompile code unless you start by deleting all .class files.
- someone once claimed that jikes and/or antmake (can't remember which) may handle this better, but I haven't actually checked.
- consequently, I always do an "ant clean install" when I do a make.
- an alternative is to write accessor methods for your constants and always use those. The final static data member can then be private and changes to it need never propagate to client classes.
As for final statics never changing - well, that's bullshit. They do not change /during execution/ but that's not the problem here.
Cheers Bent D
 Signature Bent Dalager - bcd@pvv.org - http://www.pvv.org/~bcd powered by emacs
Andreas Leitgeb - 31 Aug 2007 13:36 GMT > As far as I can recall: > - an alternative is to write accessor methods for your constants and > always use those. The final static data member can then be private and > changes to it need never propagate to client classes. Not always possible, because at certain places, java demands constants, and accessor-methods cannot be used there for obvious reasons.
> - someone once claimed that jikes and/or antmake (can't remember > which) may handle this better, but I haven't actually checked. jikes (unforunately) isn't among my options, either.
(The other paragraphs I snipped are those of which I was aware already)
Thanks. Even though it didn't really help technically, I at least felt understood :-)
Daniel Pitts - 31 Aug 2007 17:08 GMT > > As far as I can recall: > > - an alternative is to write accessor methods for your constants and [quoted text clipped - 13 lines] > Thanks. Even though it didn't really help technically, I at least > felt understood :-) The only place I can think of that java demands constants is the "case " branch of a switch statement. If thats truly what you need to worry about, you might consider using enums instead.
In any case, it is pretty common to set up your ant build.xml file to remove all .class files automatically. Specifically, to build into a separate directory tree, and nuke that whole tree. That would solve your dependency problems.
Andreas Leitgeb - 01 Sep 2007 06:04 GMT > The only place I can think of that java demands constants is the "case > " branch of a switch statement. > If thats truly what you need to worry about, you might consider using > enums instead. I can't use enums, since the project is still bound to java 1.4. And it's not only about constants. These constants are actually just one example of "incompatible changes", that would require recompilation of other classes.
> In any case, it is pretty common to set up your ant build.xml file to > remove all .class files automatically. Specifically, to build into a > separate directory tree, and nuke that whole tree. That would solve > your dependency problems. That's the "rebuild from scratch"-pattern, that I also wished to avoid. The project is large enough to make complete compilation painfully slow.
Please see also my Posting "dependency-detection in java - Take 2"
Lew - 01 Sep 2007 12:56 GMT > That's the "rebuild from scratch"-pattern, that I also wished to avoid. > The project is large enough to make complete compilation painfully slow. How slow is "painfully" slow? I remember when recompiling /one/ module took three days, when I was first learning to program. Now what does it take your recompile? Twenty minutes? An hour?
Live with it and do the recompile that you need to do. I've seen two or more answers that that is what you have to do. If it isn't acceptable, refactor your global variables not to be so global.
 Signature Lew
Andreas Leitgeb - 01 Sep 2007 18:55 GMT >> That's the "rebuild from scratch"-pattern, that I also wished to avoid. >> The project is large enough to make complete compilation painfully slow.
> How slow is "painfully" slow? Long enough that it feels painful to me. Really, I don't want to throw around with numbers, since they don't really tell anything. Would you judge for me the value per hour?
> I remember when recompiling /one/ module took three days, ... Sure, and if it took a month, our developers would probably take more care, but on the other hand, our projects would take perhaps ten times longer to finish (for all the manual checking for forgotten semicolons), so I'm rather glad about shorter compile-cycles.
> Live with it and do the recompile that you need to do. I'd like to, but I'd like to avoid any full recompiles that I don't really need - supported by tools, which either don't exist yet, or are not known to anyone answering here so far.
> I've seen two or more answers that that is what you have to do. > If it isn't acceptable, ... Of course I have to accept the current state for now, and of course I do a full recompile casually (everytime I notice that some change in a java-file doesn't have the desired runtime-effect.)
I want to trigger a general discussion about reliable dependency- management in the java-world. What I didn't originally expect nor intend were numerous similar response, suggesting to live with current state.
I do appreciate all attempts to help, but I feel sorry for helpers' time wasted in redundant replies.
Lew - 01 Sep 2007 19:08 GMT > I want to trigger a general discussion about reliable dependency- > management in the java-world. > What I didn't originally expect nor intend were numerous similar > response, suggesting to live with current state. While javac has trouble with certain dependencies, in particular the one that is vexing Andreas right now, and despite my previous comments I agree with the need to resolve it, it is superior to some other compilers in resolving dependencies at all.
I suggest setting up your Ant targes so that compiling the classes that define compile-time constants trigger targets that compile classes specifically affected by the change. This does require a build designer to analyze the dependencies by hand AFAIK, unless someone can suggest tools to help there. If a constant is global enough that freaking /every/ class depends on it, you'll get hit with compile-the-world, but for classes that have a more limited effect you'll be able to craft more limited rebuilds.
Careful attention to filesets in the source tree and how they ripple out, and careful crafting of relevant targets should make it possible for the build.xml to specify the tightest possible rebuilds without risk.
In a truly worst-case scenario you could use a custom Ant task, but it shouldn't be necessary.
 Signature Lew
Steven Simpson - 01 Sep 2007 23:09 GMT > - final statics are inlined in client classes without any reference to > where they came from and so changes to the class that defines them [quoted text clipped - 3 lines] > code unless you start by deleting all .class files. > So the inlining causes the class file to seem to not depend on the class containing the static final - which is true for actually being able to get the code running, but false as far as javac's dependency handling is concerned? And false when separate codebases are involved? Sounds like inlining is the wrong thing for javac to do, in spite of any performance gain.
If inlining by javac were disabled, could JITting do it effectively instead? I hear it's so groovy and funky these days...
 Signature ss at comp dot lancs dot ac dot uk |
Daniel Pitts - 02 Sep 2007 01:35 GMT > > - final statics are inlined in client classes without any reference to > > where they came from and so changes to the class that defines them [quoted text clipped - 9 lines] > inlining is the wrong thing for javac to do, in spite of any performance > gain. I agree. If anything, it should be inlined at class-load time, rather than at class-compile time.
> If inlining by javac were disabled, could JITting do it effectively > instead? I hear it's so groovy and funky these days... I don't know, but you have to wonder at any case that is specific to Strings and primitives. The more I think about it, the more I realize that javac can't inline regular object references, because those object instances aren't represented until runtime (unlike interned strings and primitive values).
To the OP: If you could rework any case that requires a constant (only switch's do), then you really should use a getter instead.
Andreas Leitgeb - 02 Sep 2007 21:34 GMT > I don't know, but you have to wonder at any case that is specific to > Strings and primitives. The more I think about it, the more I realize > that javac can't inline regular object references, because those > object instances aren't represented until runtime (unlike interned > strings and primitive values). Indeed: Strings, longs, floats and doubles are inlined to using class' constant pool. ints are directly inlined at each usage (e.g. as in "bipush 42"), all other objects (except Strings) are accessed through getstatic.
> To the OP: If you could rework any case that requires a constant ... I've answered that elsewhere, already.
Andreas Leitgeb - 03 Sep 2007 07:51 GMT >> I don't know, but you have to wonder at any case that is specific to >> Strings and primitives. The more I think about it, the more I realize [quoted text clipped - 6 lines] > (e.g. as in "bipush 42"), all other objects (except Strings) > are accessed through getstatic. Damn, have to correct myself: Only ints in the range of shorts are inlined. ints <-32768 or >32767 are constant-pool'ed. Otoh., long, float and double constants, for which bytecodes exist (like dconst_1) are inlined directly into code, like those short integers.
Andreas Leitgeb - 02 Sep 2007 21:10 GMT > So the inlining causes the class file to seem to not depend on the class > containing the static final - which is true for actually being able to > get the code running, but false as far as javac's dependency handling is > concerned? And false when separate codebases are involved? Sounds like > inlining is the wrong thing for javac to do, in spite of any performance > gain. No, I wouldn't go so far as to say that it was wrong. The effect could also be solved by adding some attribute (inside the .class format) that just mentions the foreign "path.class.CONST_ATTR" as having been inlined (eventually, the value could be included as well, by reference to the constant pool.) That would make it feasible to auto-generate all dependency information. (All other dependencies already show up, afterall, in the .class-file) And if the value was included as well, extra tools could auto-check that all constants are indeed consistent over all class-files.
Roedy Green - 31 Aug 2007 05:13 GMT >What is the usual "trick" to make sure that all >"B"-type classes are recompiled, when an "A"-type >class has changed? see http://mindprod.com/jgloss/javacexe.html#CIRCULAR
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Andreas Leitgeb - 31 Aug 2007 07:49 GMT >>What is the usual "trick" to make sure that all >>"B"-type classes are recompiled, when an "A"-type >>class has changed? > > see http://mindprod.com/jgloss/javacexe.html#CIRCULAR Sorry, that isn't it in this case.
First, passing "both" files to javac means pass "all" files to javac, since I'm not necessarily aware of all circular references, not even of all non-circular references.
Second, it's exactly "ant" that triggers the problem, by reducing the number of files to compile too far. (it cannot do better, though, because it hasn't got the necessary dependency-information)
Roedy Green - 01 Sep 2007 13:52 GMT >Second, it's exactly "ant" that triggers the problem, >by reducing the number of files to compile too far. >(it cannot do better, though, because it hasn't got the >necessary dependency-information) I would hope there is only as small amount of circularity. Then you can do a mini ant script to compile just those pieces, then do a big build afterward.
 Signature Roedy Green Canadian Mind Products The Java Glossary http://mindprod.com
Andreas Leitgeb - 01 Sep 2007 18:15 GMT > On 31 Aug 2007 06:49:31 GMT, Andreas Leitgeb <avl@logic.at> wrote, >>Second, it's exactly "ant" that triggers the problem, [quoted text clipped - 5 lines] > can do a mini ant script to compile just those pieces, then do a big > build afterward. The point is, I don't really know the amount of circularity and even further it could easily change with every check in.
Daniel Pitts - 01 Sep 2007 17:23 GMT > >>What is the usual "trick" to make sure that all > >>"B"-type classes are recompiled, when an "A"-type [quoted text clipped - 13 lines] > (it cannot do better, though, because it hasn't got the > necessary dependency-information) I know that IntelliJ IDEA will let you determine what classes use a constant, I'd be surprised if other IDEs didn't also. Check it out.
In any case, like I said, the only place that absolutely requires a constant is a switch statement, perhaps if you refactored that special case to an if statement, your wouldn't have that slight problem.
Although, you could come up with NoSuchMethod exceptions if you move methods around too, so its best to recompile.
Andreas Leitgeb - 01 Sep 2007 19:07 GMT >> Second, it's exactly "ant" that triggers the problem, >> by reducing the number of files to compile too far. >> (it cannot do better, though, because it hasn't got the >> necessary dependency-information)
> I know that IntelliJ IDEA will let you determine what classes > use a constant, ... "let me determine" ? I'm not sure if I parse this phrase correctly. Does it mean, it determines it for me, or asks me to determine it myself?
> I'd be surprised if other IDEs didn't also. Check it out. The IDE's I've used so far offer these features (with respect to this context) - create an ant-script and use ant for building, offering a "build" and a "build all" button. This is where this Thread's problem is *not* solved. "Reverse-dependencies" as they seem to be called are not considered. - for a certain identifier give me a list of locations where it is used. This is the right direction, but doesn't go far enough. I haven't yet seen an IDE, that would use this information automatically for rebuilding.
Did I miss any other feature that you had in mind?
Daniel Pitts - 01 Sep 2007 21:22 GMT > >> Second, it's exactly "ant" that triggers the problem, > >> by reducing the number of files to compile too far. [quoted text clipped - 19 lines] > > Did I miss any other feature that you had in mind? Nope. The real point is, if you're using a public static constant, you don't know WHO is going to use it. It might even be in another codebase altogether. This is just another one of the reasons that "Globals are bad things" :-).
Well, I hope you find the answer you want, since you don't want any of the answers you got. Good luck to you.
Andreas Leitgeb - 02 Sep 2007 09:34 GMT >> Did I miss any other feature that you had in mind? > Nope. Damn, I sure would have hoped I did ;-)
> The real point is, if you're using a public static constant, ... No, the real point is, that static final fields are just one part of a class' public interface.
Following reverse dependencies is necessary (well, apart from full rebuilds, of course) to find all bad consequences of such a change in the context of the project. E.g. adding "throws MyException" to some method is just the same beast. It may be necessary, and then I want the compiler to help me as efficiently as possible to find other classes that need to be adapted as well.
> It might even be in another codebase altogether. But then, I hopefully have some testsuite-classes inside my codebase that take care of the external interfaces. While changed constant values do not trigger errors, the values shouldn't be depended upon, anyway, beyond that it's the same in every relevant class of the codebase. The latter is guaranteed by either a full rebuild or a correct reverse-dependency-following build.
> Well, I hope you find the answer you want, since you don't want > any of the answers you got. Good luck to you. Yes, I know, I'm pickish :-) thanks.
Stefan Ram - 02 Sep 2007 02:18 GMT >What is the usual "trick" to make sure that all >"B"-type classes are recompiled, when an "A"-type >class has changed? One trick in this regard is written down in my own German-language Java course [1], but I was not aware of it when I posted to this thread recently. Now, I ran into it, and I believe this was not yet posted in this thread - but I also have not tested it again:
So, to prevent the following two constants :
public static final String text = "example"; public static final int e = 7;
from being inlined into other class files, use any runtime-only operation in their declaration, like, for example:
public static final String text = "example".toString(); public static final int e = new Integer( 7 ).intValue(); [1] I found this in the following lesson of my German language Java course in the section »Laufzeit-Initialisierungen erzwingen«:
http://www.purl.org/stefan_ram/pub/java_exemplarerzeugung_de
Andreas Leitgeb - 02 Sep 2007 21:51 GMT >>What is the usual "trick" to make sure that all >>"B"-type classes are recompiled, when an "A"-type [quoted text clipped - 8 lines] > public static final int e = new Integer( 7 ).intValue(); > http://www.purl.org/stefan_ram/pub/java_exemplarerzeugung_de This was indeed new to me, and I'll surely run into a situation someday where I'll use it, but for the case at hand it won't work, because the final static fields are autogenerated from idl-files.
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|