Java Forum / General / January 2008
[coding practises] do you declare your superclass "throws"??
jrobinss - 17 Jan 2008 16:31 GMT I've just discovered something I didn't know about.
If I have, for example, class javax.servlet.http.HttpServlet. I make my own servlet, MyServlet. I overload doGet() thus:
@Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { [...]
But then I get a warning, because I don't throw any ServletException in my code. I checked the JLS, and there it was,I can't declare *more* exceptions in the sub-class... but I can declare *less*. (see http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.4.6) So yes, the warning is justified. (even if I didn't understand everything about erasure, and when there's supposed to be a compile-time error or unchecked warning)
But this got me thinking... In future editions of the code, by other members of the team, in a year or two, will anyone be aware that they may throw ServletException but not any other one? Isn't it useful to know that this method could -- if required -- throw this particular exception?
My question is: how do you manage this, in your projects or teams? Do you declare all inherited "throw" statements (including unused ones) or do you declare only the necessary ones?
Remark: of course, declaration of useless exceptions is annoying to the caller, but in this kind of case the caller is bound to call a servlet, not my specific servlet, so the caller is bound to call the superclass's method, with all the possible throw statements.
Funny issues. -- JRobinss
Mark Space - 18 Jan 2008 01:56 GMT > But this got me thinking... In future editions of the code, by other > members of the team, in a year or two, will anyone be aware that they > may throw ServletException but not any other one? If they try, the compiler will remind them and stop. In other words, if they throw IOException at any point in the future, the compiler will say something like:
"You didn't say throws IOException on this class"
And programmer will say:
"Huh, better add that."
And that's as much time as it will take. So in summary, this is not a maintenance issue. Remove the IOException from the throws clause, and don't worry about it.
Andreas Leitgeb - 18 Jan 2008 10:24 GMT > I've just discovered something I didn't know about. > @Override > protected void doGet(...) throws ServletException, IOException { > But then I get a warning, because I don't throw any ServletException > in my code. I just wrote a simple test-case: class X { public static int foo() throws IOException { return 0; } }
and compiled it with javac 1.5.0_09 and with 1.4.2_08 and never did it write any error or warning.
Is there some fundamental difference between a ServletException (which I do not have available here for testing) and the IOException that I missed? Both seem to be derivatives from java.lang.Exception.
Or did I just misunderstand the problem?
What indeed does cause an error is an explicit try-catch for an exception that isn't actually thrown. This is, however, only annoying during development, when temporarily commenting out the actual throwing part, and then having to also comment out the try-catch.
jrobinss - 18 Jan 2008 10:48 GMT On 18 jan, 11:24, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote: [...]
> and compiled it with javac 1.5.0_09 and with 1.4.2_08 > and never did it write any error or warning. Sorry, I should have said, it's Eclipse who's generating warnings. These are configurable, and not so much linked to the language specs as a kind of help to write better code. It detects stuff like unused imports statements or variables... or useless throw statements. Anyway, the warnings themselves are not the issue, it's more what's causing them. :-)
I realize I badly explained the actual issue. For example Mark's answer is beside the point (sorry!). Of course anyone needing a new throw will be "helped" (in a forceful way) by the compiler to declare what's needed and authorized.
The idea is that there's this code, where class B extends class A, method B.n() extending method A.m(). A.m() throws MyException, B.n() doesn't need to, so its declaration does not include the throw statement. Arrives a new coder, who needs to throw an exception, because there's now a new call in the body of B.n() that raises an exception. The new coder will not be authorized to add an exception to the method, because it's overloading A.m(), so most likely s/he will add an unchecked exception (RuntimeException, or something like that). What's a shame is, the new coder could have used that MyException. Only it wasn't apparent, because it was declared nowhere in B. New coder could have gone to class A, but after all, when editing the implementation of a class you don't always check all superclasses and interfaces for possibilities (or do you?). And sometimes they are hidden away in a jar and you don't have the code, so it's not easy to browse them.
As an example, new coder could write...
/** * note from new coder: would like to throw ServletException, but can't because it's an overload */ @override public void someMethod() { try { doStuffThatThrowsServletException(); } catch (ServletException se) { throw new RuntimeException("", se); } }
...when it would have been possible to write...
/** * note from new coder: I added ServletException! */ @override public void someMethod() throws ServletException { doStuffThatThrowsServletException(); }
I realize while writing this that most people will probably advise me to write off the useless throw statements and trust further coders to do a minimal research job. I simply wish coding was so simple, personaly I see so much approximate coding everywhere that I like guidelines. :-) Adn I wanted to know what other programmers were doing. (which is what NGs are for, ain't it? :-) )
Hoping to be more clear! -- JRobinss
Andreas Leitgeb - 18 Jan 2008 11:21 GMT > Sorry, I should have said, it's Eclipse who's generating warnings.
> The idea is that there's this code, where class B extends class A, > method B.n() extending method A.m(). A.m() throws MyException, B.n() > doesn't need to, so its declaration does not include the throw > statement. I take it that the override in B of course also must be name "m" :-)
I understand your being concerned about future developers, who might not know, that adding ServletException to that particular method is ok, and I want to add an even stronger motive to leave the S.E. in the throws-list: A future programmer might want to derive his class C from your class B, and then feel the need to throw a S.E. from his C.m . *There* he can no longer add the exception to the throws-list.
> I realize while writing this that most people will probably advise me > to write off the useless throw statements and trust further coders to > do a minimal research job. No, quite the opposite: If you have a feeling that either your method, or any method overriding yours may have a legitimate point for throwing a ServletException, you really should list it in your method's throw- list, but don't feel overly responsible for yet unknown derive class' needs. As a rule of thumb, leave in those exceptions that are not semantically at odds, with what your class is designed for.
If a derived class *unexpectedly* needs to throw ServletExceptions, it can still pass it as rootCause to the IOException :-) If your class doesn't deal with Servlets (e.g. doesn't even call baseclass' method) and is not directly designed to accomodate for Servlet-related sub-classes, then eclipse's advice probably applies.
Configure that warning away in eclipse if it bugs you. Eclipse is trying to help, but if you know better after having considered Eclipse's advice, then eclipse's advice is the problem, and should be solved inside eclipse rather than worked around in java-code.
jrobinss - 18 Jan 2008 12:42 GMT Thanks a lot for a useful and insghtful response. (as they say in French, "tout flatteur vit aux dépens de celui qui l'écoute", ha ha)
On 18 jan, 12:21, Andreas Leitgeb <a...@gamma.logic.tuwien.ac.at> wrote:
> I take it that the override in B of course also must be name "m" :-) Well, in fact, say that to the authors of JLS, whom I took this naming from. (nah, in fact they don't use method name m and n, they call the methods m and n, which is a semantic nitpick but answers your comment).
> A future programmer might want to derive his class C from your class B, > and then feel the need to throw a S.E. from his C.m . *There* he can > no longer add the exception to the throws-list. Good point.
> As a rule of thumb, leave in those exceptions that are not > semantically at odds, with what your class is designed for. I agree.
In fact, this more or less means that as a rule of thumb, ignore Eclipse's warning that this "throws" is useless... Eclipse knows only about the implementation, not the design. :-)
Thanks -- JRobinss
Lew - 18 Jan 2008 14:16 GMT > Thanks a lot for a useful and insghtful response. > (as they say in French, "tout flatteur vit aux dépens de celui qui [quoted text clipped - 23 lines] > Eclipse's warning that this "throws" is useless... Eclipse knows only > about the implementation, not the design. :-) Also this concern for "future developers who may want to ..." is beside the point. If you think the class you're writing is going to need ServletException thrown by that method later, why would you remove it now? The idea is to write the code to avoid the need for later modification if possible - make it reusable rather than easily modifiable.
The thing that is easiest for future developers isn't to be able to change your code, it's not to need to.
 Signature Lew
Lew - 18 Jan 2008 14:31 GMT > Also this concern for "future developers who may want to ..." is beside > the point. s/beside/exactly/
 Signature Lew
Andreas Leitgeb - 18 Jan 2008 14:38 GMT > Also this concern for "future developers who may want to ..." is beside the > point. If you think the class you're writing is going to need > ServletException thrown by that method later, why would you remove it now? Whether it will be a future developer, or oneself at a later time generally turns out to be principially the same thing: Even oneself then likely has forgotten, whatever the other future developer just doesn't know. :-)
It was about weighing the quality of eclipse's advice (to remove exceptions from throws-clause that are at the current moment not thrown). The answer being: it depends on things that eclipse cannot know.
Lew - 18 Jan 2008 14:52 GMT >> Also this concern for "future developers who may want to ..." is beside the >> point. If you think the class you're writing is going to need [quoted text clipped - 9 lines] > thrown). The answer being: it depends on things that eclipse > cannot know. Indeed, and I agree with your conclusions.
My strategy for being kind to that future person is to follow your advice in the case of the overridden method signature retaining ServletException, since it's part of the expectation from the superclass. This guarantees that use of my custom subclass will be consistent with that of its superclass whether further extended or no. This is consistent with theoretical foundations like Liskov substitution. <http://en.wikipedia.org/wiki/Liskov_substitution_principle>
In this case, I'm extending the notion to the class itself, imputing a property q(T) that one can extend T with a further subclass, X, and declare the overridden method to throw ServletException. A subclass S that does not include ServletException in that method's signature would not be substitutable in the 'extends' clause of X.
 Signature Lew
Andreas Leitgeb - 18 Jan 2008 18:53 GMT > My strategy for being kind to that future person is to follow your advice in > the case of the overridden method signature retaining ServletException, since > it's part of the expectation from the superclass. I wouldn't go as far as making it a general, all-time-valid rule.
If I had a class that wraps integers, and a method that was only usable on odd integers and threw an EvenException for even ones, then a subclass dealing with only odd integers would remove the EvenException from its overrided method's throws-clause, because it makes no sense for that class, nor for any further subclass of it :-)
> This is consistent with theoretical foundations like Liskov substitution. ><http://en.wikipedia.org/wiki/Liskov_substitution_principle> Interesting concept, but I think you're overstretching it to a point were rendering it a strict equality relation is not far away, thus voiding the whole subclass-concept.
> In this case, I'm extending the notion to the class itself, imputing a > property q(T) that one can extend T with a further subclass, X, and declare > the overridden method to throw ServletException. That's like: some q(Object) is "can be a String or an Integer." This property is not retained by Integers, so Integers aren't really a subtype of Object ;-)
Ben Phillips - 21 Jan 2008 19:03 GMT > I just wrote a simple test-case: > [quoted text clipped - 4 lines] > and compiled it with javac 1.5.0_09 and with 1.4.2_08 > and never did it write any error or warning. This is interesting. It could stand to give a warning in this case, or where it's final or private. The rest of the time, no error or warning seems best, since even if you don't throw it yourself you may be intentionally declaring that overridden versions may throw it.
> What indeed does cause an error is an explicit > try-catch for an exception that isn't actually > thrown. This is, however, only annoying during > development, when temporarily commenting out the > actual throwing part, and then having to also > comment out the try-catch. Very annoying. This one should be a warning rather than an error, IMO. Unreachable code in general should be.
Lew - 21 Jan 2008 19:24 GMT >> I just wrote a simple test-case: > > [quoted text clipped - 8 lines] > seems best, since even if you don't throw it yourself you may be > intentionally declaring that overridden versions may throw it. Not with static methods, because one cannot override a static method.
>> What indeed does cause an error is an explicit >> try-catch for an exception that isn't actually [quoted text clipped - 4 lines] > Very annoying. This one should be a warning rather than an error, IMO. > Unreachable code in general should be. Unreachable code should be what? Should be a warning rather than an error?
Java's philosophy tends to be to check as much as can be checked at compile time. Your feelings about what "should be" will have to concede to what is.
Java does have a Request for Enhancment (RFE) process.
Some IDEs, such as Eclipse, let you adjust the severity of some of their internal compiler messages (e.g., make a warning rather than an error).
 Signature Lew
Ben Phillips - 23 Jan 2008 23:15 GMT >>> class X { public static int foo() throws IOException { return 0; } >>> } [quoted text clipped - 8 lines] > > Not with static methods, because one cannot override a static method. That was my point -- it could stand to give a warning with static methods and with private or final ones, though it shouldn't with overridable methods.
>>> What indeed does cause an error is an explicit >>> try-catch for an exception that isn't actually [quoted text clipped - 6 lines] > > Unreachable code should be what? Should be a warning rather than an error? Yes, since it's not actually incorrect and since making it an error causes inconvenience. Since it is "strange" or a potential sign of trouble, it shouldn't be silent either; hence a warning, which is what's traditionally used for things that may be OK but may be a sign of a programming logic error.
> Some IDEs, such as Eclipse, let you adjust the severity of some of their > internal compiler messages (e.g., make a warning rather than an error). This is quite useful, yes.
Lew - 24 Jan 2008 00:55 GMT Lew wrote:
>> Unreachable code should be what? Should be a warning rather than an >> error?
> Yes, since it's not actually incorrect and since making it an error > causes inconvenience. I'm afraid that it is actually incorrect, in that it violates the Java Language Standard.
<http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21>
It's just as incorrect as any other violation of the Standard.
The law is the law.
 Signature Lew
Andreas Leitgeb - 24 Jan 2008 07:04 GMT > Lew wrote: >>> Unreachable code should be what? Should be a warning rather than an >>> error? >> Yes, since it's not actually incorrect and since making it an error >> causes inconvenience.
> I'm afraid that it is actually incorrect, in that it violates the Java > Language Standard. > <http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21> This is a circular, since this part of the JLS is the very point we(Ben and me) are criticizing.
The "law" appears to me like a state-law against "silly walks". Not that the latter were all that useful, but why forbid them?
Lew - 24 Jan 2008 14:15 GMT >> Lew wrote: >>>> Unreachable code should be what? Should be a warning rather than an [quoted text clipped - 11 lines] > The "law" appears to me like a state-law against "silly walks". Not that > the latter were all that useful, but why forbid them? It's not circular. You are essentially asking a telepathy question. Because your esthetic is somehow offended by a rule that eliminates by design a useless and possibly maintenance-damaging wart from programs that are /supposed/ to be durable, you guys whine that it's "inconvenient" and try to second-guess the intent of the designers. The fact is that it clearly /was/ the intent to prevent useless extra unreachable code, and that formal reasoning about the program would be eaiser for the compiler if this became a language requirement. The language is defined by its very rules - accusing me of "circular" reasoning by reference to those rules is specious.
The Java designers clearly felt that this was a fundamental and important issue - the section on unreachable code is one of the most detailed and rigorous in the JLS. Clearly they felt it was vitally important, as you will discover if you read that part. It seems to my eye that it's one of the fundamental things that make Java what it is, based on how much care they put into the matter.
Now you apparently disagree with that reasoning. That is fine. But that doesn't make you right, or change the fact that reachability is one of the fundamental design points that make Java the language that it is. Java is designed to avoid problems, not invite them, and to create durable software that will be maintainable.
Really the argument should be on the other side - why should unreachable code be tolerated at all? There must be a name for the logical fallacy that throws the burden of proof on the wrong party.
 Signature Lew
Ben Phillips - 25 Jan 2008 03:37 GMT > It's not circular. Sure it is.
> You are essentially asking a telepathy question. > Because your esthetic is somehow offended by a rule that eliminates by > design a useless and possibly maintenance-damaging wart from programs > that are /supposed/ to be durable, you guys whine that it's > "inconvenient" and try to second-guess the intent of the designers. But there's now at least one documented case where the standard *causes* inconvenience. Right now you sometimes can't test a change or comment out one line of code without commenting out a whole block of code somewhere else, AND another line or two in other places, in a manner that is somewhat awkward. For example one line in a try block being commented out or a change there tested may require commenting out the try line, some distance above, and an entire catch block below, ultimately forming three disjoint pieces of code. Easy to miss that these three commented-out regions should really be commented back in together as a single unit later on. Also more work. Some other cases like this are logically unavoidable: if you comment out a declaration you will clearly need to comment out every use of the declaration. The try...catch case is not inherently unavoidable this way. It occurs because of an arguably-gratuitous "feature" of the standard rather than inevitable logic. Declarations are also not as often commented out or experimented with in this sort of manner. The only cases I've ever run into that've annoyed me have involved try...catch and switch, the latter when the cases become or stop being exhaustive and the default sometimes needs commenting out.
A warning suffices to alert that this code is not polished enough for release, as a general rule.
Also, vast amounts of dead code that confound maintenance programmers take the form of entire methods and even whole classes that lie about collecting dust. None of these seems to generate an error with the javacs I've used. In the non-private case, the compiler can't be sure the code won't be linked with code that calls these methods, though, so there is nothing it can do. I do seem to recall private methods that aren't used generating a warning with one, but not an error.
Requiring dead code to be commented out would be reasonable if it were easy to do so without the problems described above for try...catch. Default blocks and entire unused private methods are easy to comment out because they are single contiguous chunks of code. Commenting out a catch is another matter. Perhaps a compromise would be to allow a nilpotent try block -- a try { stuff } with no catch or finally clauses.
I suppose a workaround is to have a dummy finally clause containing only a comment on every try block that doesn't have a "real" finally clause. Then you can comment out a catch block without a complaint, even if it's the sole catch block. This saves commenting out the try line. It still means commenting in or out the throw in the try body and the catch clause as a unit, but at least you will generally get an obvious reminder to keep them in synch as the throw without the catch will, in many cases, result in the compiler complaining that it's not declared or handled (checked exceptions not thrown by the method being edited) and the catch without the throw will get the current dead-code complaint.
Dummy finally clauses seem ugly to me, though, and a way to clutter code with unhelpful and gratuitous crud -- the exact sort of thing the standard here is argued to be trying to reduce.
Another compromise would be to permit an empty catch clause for an unthrown exception. Then you could comment out the catch block's innards and again save having to comment out the try line.
Warnings make sense in all of these cases (any try with no catch or finally blocks that contain actual code) both to catch this sort of temporary hack before release so it can be removed or otherwise fixed (e.g. by uncommenting code you forgot to uncomment-out in a catch block) and to catch some unrelated and common bad coding practises, such as to catch and discard actually-thrown exceptions without taking any action.
This last assumes that a shop has a policy of not shipping as final (or even beta) any code that generates warnings, and likewise requires real justification for every @SuppressWarning use in production code. I hope that that is considered basic common sense in every Java shop though.
> formal reasoning about the program would be > eaiser for the compiler if this became a language requirement. This is just plain wrong. To support the current standard, the compiler has to determine which code is provably-dead-by-static-analysis and then complain if there is any dead code detectable in this manner. The formal reasoning in question can be supported if the compiler allows dead code at the cost of simply performing the same static analysis and then ignoring whatever it detects to be dead code (other than to emit a warning). In other words, the compiler is required by the standard to perform the same analysis that is needed anyway. Formal reasoning is exactly as easy (or hard) either way.
> The > language is defined by its very rules - accusing me of "circular" > reasoning by reference to those rules is specious. Not when those rules themselves are the subject of discussion. If we were discussing whether some construct was legal in current Java, appeal to the rules would not only be valid but the obvious way to definitively answer the question. But we were not; we were discussing whether or not it is desirable to *change* one of those rules, and there arguing that it's not because the rules are the rules amounts to declaring by fiat that the status quo is invariably preferable to any change, without proving this. Such an attitude would, if held by Sun itself, have us still using the clunky for (Iterator x = y.iterator(); x.hasNext();) to loop over collections. (And lacking the type-safe generics we now enjoy, but I think less people are enamored of generics as of the new for loop. :))
> The Java designers clearly felt that this was a fundamental and > important issue - the section on unreachable code is one of the most > detailed and rigorous in the JLS. Clearly they felt it was vitally > important, as you will discover if you read that part. That is not in dispute. Whether they actually were correct is under discussion, not whether they felt strongly that they were correct.
> Now you apparently disagree with that reasoning. That is fine. But > that doesn't make you right Nor does the existing wording of the JLS automatically make us wrong.
> or change the fact that reachability is one > of the fundamental design points that make Java the language that it > is. Java is designed to avoid problems, not invite them, and to create > durable software that will be maintainable. I fail to see how warnings don't suffice, given a reasonable policy of not letting code that generates warnings (or use of @SuppressWarning to hide problems instead of solely in the rare and necessary cases involving interfacing generics to arrays or legacy ungenerified code) get out of alpha until the causes of the warnings are gone.
> Really the argument should be on the other side - why should unreachable > code be tolerated at all? There must be a name for the logical fallacy > that throws the burden of proof on the wrong party. As far as I'm aware, there is none. Nor is there any clear indication that the burden of proof *is* on the wrong party here. Nobody is asserting anything here entirely without evidence; you've pointed to the standard, while we've pointed to an annoyance we've observed in actual practise that may warrant amending that standard. Reducing the error to a warning for the specific case of a catch clause for an unthrown exception would be a fairly narrow and specific change and doesn't seem wholly unjustified.
Perhaps the issue will become moot with smarter IDEs. Eclipse is already surprisingly smart about some things, and so is NetBeans. Before long it might be able to automatically comment out a catch block for an exception no longer thrown, comment out the try line if there are no "live" catch or finally clauses, and comment these back in if one of the exceptions becomes thrown again, recognizing commented-out try lines and catch blocks as something to uncomment if a matching exception throw suddenly (re)appears between the try and the catch in question. Essentially it would just require it to fix dead-code errors itself by commenting out the offending code and the "other end" of the same brace structure if there is one, and fix unhandled-exception errors by finding a commented out catch that can handle it and uncommenting it (and any matching commented-out try line, the nearest above it and at the same nesting level) if possible.
Even a manual comment-out-clause and uncomment-clause command pair that is smart enough to balance braces would improve this case a lot.
And ultimately it probably IS easier and likelier for the IDEs to change than the JLS to change. Then again, Java 7 is apparently in the works and fairly radical changes like reified generics are being contemplated. Now may be a time when JLS changes are a bit more feasible.
It remains to question whether the suggested change would be desirable. I'm not 100% sure myself.
Andreas Leitgeb - 25 Jan 2008 09:13 GMT > Default blocks and entire unused private methods are easy to comment out > because they are single contiguous chunks of code. No, not even these are, since if the currently commented out line (or block or method) happens to contain the one and only call to yet another private method, then I'd enter a chain of methods to comment out each separately, and re-activate them when re-activating that one initial line/block/method.
Otoh, if rather than commenting stuff out I prepend it with "if (false)", then the code is still dead, and the compiler doesn't even write a warning.
But "if (false)"ing is still no substitute, since it still requires the thusly deaktivated part to still be compileable.
Also, I just tried: unused private methods do *not even* raise a warning in javac (this seems to be an eclipse-feature). I consider unused private methods to be the principially same thing as unused default-blocks in exhaustive switches and catches for unthrown exceptions. Actually, if/while-statement-bodies, whose condition can be determined as always-false could also be determined as dead code, but only if the consequence were not worse than a warning, since that's probably the most-used workaround for the annoying feature under discussion.
I'd find it reasonable that all of them threw warnings.
But then again, maybe we're indeed barking up the wrong tree, and what we really want is a compiler that, based on some options, deviates from JLS to not overly annoy for code still under active development.
I can agree to both Lew and JLS in that code that is shipped should not contain any such dead blocks.
> It remains to question whether the suggested change would be desirable. > I'm not 100% sure myself. Lew - 25 Jan 2008 14:42 GMT >> Default blocks and entire unused private methods are easy to comment out >> because they are single contiguous chunks of code. [quoted text clipped - 34 lines] >> It remains to question whether the suggested change would be desirable. >> I'm not 100% sure myself.
 Signature Lew
Lew - 25 Jan 2008 14:54 GMT Lew wrote - actually, he didn't, he pressed SEND first.
Sorry about the accidental SEND before replying. Please disregard that.
Andreas Leitgeb wrote:
>> Otoh, if rather than commenting stuff out I prepend it with "if (false)", >> then the code is still dead, and the compiler doesn't even write a >> warning. If it did, it would violate the JLS.
>> But "if (false)"ing is still no substitute, since it still requires >> the thusly deaktivated part to still be compileable. But not necessarily compiled. Anyway, the whole point of that section is to lock down one type of incorrect code. You guys are arguing that Java should be more tolerant of that variety of incorrect code. Java is saying, "Tough noogies." I'm agreeing with Java. Having a compiler call bad code an error is not the worst flaw in the Java language.
>> Also, I just tried: unused private methods do *not even* raise >> a warning in javac (this seems to be an eclipse-feature). I consider Good point. It should. Java should be more strict, not more lax.
>> unused private methods to be the principially same thing as unused >> default-blocks in exhaustive switches and catches for unthrown [quoted text clipped - 3 lines] >> since that's probably the most-used workaround for the annoying >> feature under discussion. There is a difference in the language spec between how conditions are handled in if statements and how they're handled in while statements.
>> I'd find it reasonable that all of them threw warnings. The Java designers went through a great deal of trouble to define if (false) to allow conditional non-compilation without it being an error.
JLS <http://java.sun.com/docs/books/jls/third_edition/html/statements.html#14.21> /op. cit./ upthread:
> if (false) { x=3; } > does not result in a compile-time error. > An optimizing compiler may realize that the statement > x=3; will never be executed and may choose to omit the code for that > statement from the generated class file, but the statement x=3; is > not regarded as "unreachable" in the technical sense specified here. I'm not entirely sure I read your message correctly, but it seemed to take issue with that feature.
 Signature Lew
Andreas Leitgeb - 25 Jan 2008 16:22 GMT >> if (false) { x=3; } >> does not result in a compile-time error. > I'm not entirely sure I read your message correctly, but it seemed to take > issue with that feature. There are certain samples which I consider "the same in principle", but JLS has defined different behaviour for:
on one hand: never-called private methods. if (false) { ... } and while(false) {...} and also if (true) {} else { ... }, for (;false; ...) { ... }. extraneous exceptions in throws-clause of a private method. (ok, not exactly "code", but additional items in the methods "Exceptions"-attribute) probably another couple of such things
on the other hand: un-reachable catch-blocks un-reachable switch-default-blocks. probably another couple of such things
While first hand is defined by JLS to be entirely "ok", the other hand is defined by JLS to be entirely not ok.
While the former do allow dead-code to exist in currently-legal java-code, thusly thwarting the proclaimed goal of avoiding dead code, the latter is a nuissance during development phase justified in the name of avoiding dead code.
In principle they are all the same, namely dead code, and all of these would be defined to yield (just) warnings in my fictive ideal JLS. :-)
Position clear now? Dare to contradict me??? ;-)
Lew - 25 Jan 2008 23:16 GMT > There are certain samples which I consider "the same in principle", > but JLS has defined different behaviour for: [quoted text clipped - 17 lines] > While first hand is defined by JLS to be entirely "ok", > the other hand is defined by JLS to be entirely not ok.
> Position clear now? Dare to contradict me??? ;-) Actually, the JLS defines different behavior for the if() and while() conditions.
 Signature Lew
Andreas Leitgeb - 26 Jan 2008 13:38 GMT >> on one hand: >> never-called private methods. >> if (false) { ... } and while(false) {...} >> Position clear now? Dare to contradict me??? ;-) > Actually, the JLS defines different behavior for the if() and while() conditions. Indeed, "while (false) ..." is illegal ... Well then consider it moved to the "other hand", and my point is (imho) still valid.
PS: "while (i==1.5) { ... } *is* legal for an "int i" :-) But, admittedly, that's not the point under discussion ;-)
Lew - 26 Jan 2008 14:36 GMT > PS: "while (i==1.5) { ... } *is* legal for an "int i" :-) > But, admittedly, that's not the point under discussion ;-) It's an interesting point, nonetheless.
This cannot be proven at compile time to fail, at least not without considerable semantic analysis beyond what compilers really should do.
It requires that the compiler understand that the double-promoted value of an int can never have a fractional part, an assumption that would fail for long btw, and that the other operand does have a fractional part - it could do that, but that's a lot of work for compile-time. As you've noted, Java's rules about unreachable code didn't try to lock down all the scenarios - in particular they don't lock down anything that requires run-time analysis of the operations. Even more particularly, they don't lock down expressions where you don't know all the values at compile time. Even though the promoted value of 'i' can be predicted not to equal 1.5, it cannot be predicted what it will equal.
So 'while ( i == 1.5 )' for an int i passes the compile-time check for reachability. The rules don't account for any run-time actions, like binary promotion, even ones where one "could know" what the result will not be.
 Signature Lew
Joshua Cranmer - 26 Jan 2008 14:55 GMT >> PS: "while (i==1.5) { ... } *is* legal for an "int i" :-) >> But, admittedly, that's not the point under discussion ;-) [quoted text clipped - 3 lines] > This cannot be proven at compile time to fail, at least not without > considerable semantic analysis beyond what compilers really should do. What about optimizing compilers utilizing constant value propagation and dead code elimination? If the set of values of i can be known at compile-time (e.g., the previous statement is "int i=5;"), then it stands to reason that a compiler should figure out that 5 != 1.5 and remove the while block.
 Signature Beware of bugs in the above code; I have only proved it correct, not tried it. -- Donald E. Knuth
Lew - 26 Jan 2008 17:08 GMT >>> PS: "while (i==1.5) { ... } *is* legal for an "int i" :-) >>> But, admittedly, that's not the point under discussion ;-) [quoted text clipped - 9 lines] > stands to reason that a compiler should figure out that 5 != 1.5 and > remove the while block. That is a run-time consideration and doesn't bear on the issue of what is "unreachable" code according to the language specification.
You're speaking of the Hotspot compiler, the bytecode-to-machine code compiler. This discussion focused on javac, the Java-source-text-to-bytecode compiler.
 Signature Lew
Wayne - 28 Jan 2008 13:55 GMT > ... > It requires that the compiler understand that the double-promoted value > of an int can never have a fractional part, an assumption that would > fail for long btw, ... This has been an interesting thread, but I'm not sure I understand the above (off-off-topic :-). When can a long promoted to double contain a fraction? Do you have any examples?
-Wayne
Lew - 28 Jan 2008 16:14 GMT >> ... >> It requires that the compiler understand that the double-promoted [quoted text clipped - 4 lines] > the above (off-off-topic :-). When can a long promoted to double > contain a fraction? Do you have any examples? Any long with more than 53 significant bits.
A double cannot capture all integral values because long has a higher resolution. So when you promote a long to a double you could end up with an approximation to the original value.
You are right, that number will not have a fractional part; I misspoke. What I meant was that the value will be off by a fractional part of the magnitude, which of course is still an integral amount of error.
What I should have pointed out is that a double-to-long comparison could fail even if both values are integral, if the values exceed 53 bits of precision. This still supports the primary original point that the compiler is not really free to define "unreachable" in terms of run-time analysis, not in the restricted sense defined by the JLS.
Thanks for spotting the mistake.
 Signature Lew
Ben Phillips - 28 Jan 2008 04:28 GMT >>Default blocks and entire unused private methods are easy to comment out >>because they are single contiguous chunks of code. [quoted text clipped - 4 lines] > comment out each separately, and re-activate them when re-activating > that one initial line/block/method. These methods could be made a single contiguous block within the source file. Then it's only one block to comment out.
> Otoh, if rather than commenting stuff out I prepend it with "if (false)", > then the code is still dead, and the compiler doesn't even write a > warning. Interesting. I wasn't sure if this would work as a workaround, since the code is still provably dead by static analysis.
> But "if (false)"ing is still no substitute, since it still requires > the thusly deaktivated part to still be compileable. If you're not editing that part, and didn't remove some declaration needed for it to be compilable, this should not be a problem. The situation under discussion had been where editing in one area makes code elsewhere that you'd rather not touch yet become unreachable, after all.
> Also, I just tried: unused private methods do *not even* raise > a warning in javac Yes, I noticed. It's an example of inconsistency in applying principles from the JLS. I'd suggest it become a warning, and as a compromise the unused default/catch block errors also become warnings. :)
> I'd find it reasonable that all of them threw warnings.
> But then again, maybe we're indeed barking up the wrong tree, and > what we really want is a compiler that, based on some options, > deviates from JLS to not overly annoy for code still under active > development. Isn't that overloading the purpose of the warning/error distinction? Warnings meaning "this may work, but it looks dodgy and at minimum needs polish" for the most part, and errors typically meaning "this cannot work, at all".
> I can agree to both Lew and JLS in that code that is shipped should > not contain any such dead blocks. Ditto. Of course I firmly believe that code that is shipped should not generate any compiler warnings, and not merely because of gratuitous use of the @SuppressWarning annotation everywhere either, though sometimes it's justifiable especially when dealing with generics-induced messes.
>>It remains to question whether the suggested change would be desirable. >>I'm not 100% sure myself. Is this supposed to be the end of your post? If not, my newsserver seems to have truncated their copy of your post. I can't find any way to "refresh" it in Thunderbird as I would a web page in Firefox, so I can't see if their master copy is truncated or only the copy they sent me (or, if the latter, actually get the rest of it, it seems! Not without resubscribing and clobbering all of my read/unread info for comp.lang.java.programmer anyway).
Andreas Leitgeb - 28 Jan 2008 09:08 GMT >> No, not even these are, since if the currently commented out line >> (or block or method) happens to contain the one and only call to >> yet another private method, ... > These methods could be made a single contiguous block within the source > file. Then it's only one block to comment out. They could be, but probably they aren't ;-) Commenting out a whole group of consecutive methods will most likely also include one or two methods still needed elsewhere...
> Yes, I noticed. It's an example of inconsistency in applying principles > from the JLS. I'd suggest it become a warning, and as a compromise the > unused default/catch block errors also become warnings. :) As it seems, the "founding fathers" of java did intend for "if(false)" to also solve the temporarily-no-throws problem, in that the body of a if(false) may contain the only throw-source for a checked exception, and then the according catch is no longer stale in javac's sense, even though no bytecode is emitted for that if's body.
Even more interestingly, some experiment of mine shows, that even for the catch-clause, in this case no bytecode is generated! Thus
class Y extends Exception {} public class X { public static void main(String[] args) { try { if (false) { foo(); } } catch (Y e) { e.printStackTrace(System.out); } } static private boolean foo() throws Y { return false; } }
The bytecode generated for main() is no more than: 0: goto 3 3: return (so, either the if or the try is not entirely traceless :-)
> Warnings meaning "this may work, but it looks dodgy and at minimum needs > polish" for the most part, and errors typically meaning "this cannot > work, at all". That's exactly how I see it.
>>>It remains to question whether the suggested change would be desirable. >>>I'm not 100% sure myself. > Is this supposed to be the end of your post? Sorry for the confusion I caused. During writing that post, I was distracted a couple of times, and when seeing the next distraction approaching, I sent it off, having forgotten that the last line was yet unanswered.
The error->warning for unreachable code is 100% desirable in my eyes. Issueing new warnings for unused private methods and if(false) actually less so, since that would effectively be an incompatible change, afterall.
Lew - 28 Jan 2008 16:17 GMT > The error->warning for unreachable code is 100% desirable in my > eyes. Issueing new warnings for unused private methods and > if(false) actually less so, since that would effectively be an > incompatible change, afterall. Particularly incompatible would be the 'if (false)' change, since the founders went through so much trouble to make it work the way that it does.
 Signature Lew
Ben Phillips - 25 Jan 2008 03:04 GMT > Lew wrote: > [quoted text clipped - 6 lines] > I'm afraid that it is actually incorrect, in that it violates the Java > Language Standard. You misunderstand me. I don't mean to say that it doesn't violate the Java Standard. I mean to say that having dead code doesn't logically prevent the program from being compilable and runnable; the standard could hypothetically be amended to allow dead code without the result being that there was an irredeemable ambiguity or other problem with implementing a compiler to follow the changed standard, or a breakdown of any of the core of Java's "social contract" with coders and users, such as that it is fairly strongly type-safe, memory/pointer-safe, and secure in particular ways (JNI and reflection shenanigans, including hex-editing serialized objects, notwithstanding).
In fact, arguing based on what the standard currently says in a debate about whether an aspect of the standard itself is optimal seems a little bit circular to me...
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 ...
|
|
|