Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / January 2008

Tip: Looking for answers? Try searching our database.

[coding practises] do you declare your superclass "throws"??

Thread view: 
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 Magazines

Get 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 ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.