Bug 95868 - Autoboxing/unboxing problem with conditional values that may be null?
Summary: Autoboxing/unboxing problem with conditional values that may be null?
Status: RESOLVED WONTFIX
Alias: None
Product: JDT
Classification: Eclipse Project
Component: Core (show other bugs)
Version: 3.1   Edit
Hardware: PC Linux
: P3 normal (vote)
Target Milestone: 3.1 RC1   Edit
Assignee: Philipe Mulet CLA
QA Contact:
URL:
Whiteboard:
Keywords:
Depends on:
Blocks:
 
Reported: 2005-05-18 18:08 EDT by Luke Hutchison CLA
Modified: 2005-05-20 01:56 EDT (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Luke Hutchison CLA 2005-05-18 18:08:30 EDT
I get a NullPointerException running the following code when yKey does not exist
as a key in the HashMap y:

    HashMap<String,Integer> y = getHashMap();
    Integer w = (x.equals("X") ? 0 : y.get(yKey));

What appears to be happening is this is interpreted as:

    Integer w = new Integer(x.equals("X") ? 0 : (int) y.get(yKey));

rather than

    Integer w = (x.equals("X") ? new Integer(0) : y.get(yKey));

which is probably what should happen.  (Unless it is defined otherwise in the
autoboxing/unboxing spec?)

That way I can test if (w == null) after this assignment.

The current behavior caused a hard-to-trace bug, and is not very intuitive.

Thanks!
Comment 1 Philipe Mulet CLA 2005-05-18 18:50:21 EDT
I presume you saw it in M7?
Comment 2 Luke Hutchison CLA 2005-05-18 23:29:13 EDT
Yes, I believe it was 3.1M7, although it could have been 3.1M6 (I'm at home
right now so I can't check).  Let me know if you need the version number for sure.

One thing I should additionally mention is that the former case always performs
an unbox followed by an autoboxing, whereas the latter case performs just an
autoboxing, and only if the condition is true (otherwise it does no
unboxing/autoboxing).  So the current behavior is actually less efficient than
the ideal, as well as the problem I mentioned where a null pointers exception is
thrown when it doesn't need to be.
Comment 3 Luke Hutchison CLA 2005-05-18 23:32:25 EDT
Actually, sorry that is not quite correct -- the "former case" (the current
behavior) is to perform an unboxing only if the condition is false, although it
always has to do the autoboxing step.  So it's still less efficient than it
could be, but it may not be quite as bad efficiency-wise as I described,
depending on how often the condition is true.

I don't have any easy way to test this on Sun's compiler right now -- how does
Sun compile this expression?
Comment 4 Philipe Mulet CLA 2005-05-19 04:58:23 EDT
Javac agrees with us, and
http://java.sun.com/j2se/1.5.0/docs/guide/language/autoboxing.html
mentions this scenario as legite:

"[...]. The result of all this magic is that you can largely ignore the
distinction between int and Integer, with a few caveats. An Integer expression
can have a null value. If your program tries to autounbox null, it will throw a
NullPointerException. [...]"

Added AutoboxingTest#test104
Comment 5 Philipe Mulet CLA 2005-05-19 05:00:23 EDT
Now auto-unboxing here remains questionnable, feels like the conditional
operator should be smarter at noticing some of its operand need nothing.
Comment 6 Philipe Mulet CLA 2005-05-19 05:07:28 EDT
JLS3 15.25 expects this behavior. Both operands are convertible to primitive
type 'int', thus the type of operation is 'int'. Then it needs boxing to match
assigned variable type 'Integer'.
Comment 7 Philipe Mulet CLA 2005-05-19 05:10:01 EDT
Closing since working as spec'ed
Comment 8 Luke Hutchison CLA 2005-05-19 10:46:54 EDT
Salut Phillipe,

Thanks for doing the work to figure out what the correct behaviour is supposed
to be.

Is it possible that Eclipse could just report a warning here?  It is entirely
possible to avoid the implicit NullPointerException if the code is reworked as
an if statement rather than as a (?:) statement.  That seems very
counter-intuitive to me, and it took me a while to figure out why I was getting
an exception there.  So the following code will never throw an exception:

Integer w;
if (x.equals("X"))
  w = 0;
else
  w = y.get(yKey);

Up until now I have never seen a case where (?:) and an if statement like the
above do not behave identically.  (The only difference, before
autoboxing/unboxing, is that an if statement like that would implicitly take
care of polymorphism without a cast, and (?:) may not do so -- perhaps this
corresponds to the behaviour in JLS3 15.25?)

It is also possible that while the current behavior is correct according to JLS3
15.25, that some earlier Java standard about the exact semantics of (?:) is
actually being violated.  Whether or not it is, this certainly goes counter to
intuition.

So is an Eclipse warning in order, just so the NullPointerException could be
avoided if the programmer is notified?  I have a gut feeling too that other
situations like this could arise too where an exception could be avoided, or at
least where it's easy to detect that the user is doing something where they may
not realize that an exception could be thrown.

I forsee autoboxing/autounboxing becoming so "accepted" that nobody ever thinks
about what's going on "under the hood", and this could give rise to a whole new
class of software bugs where exceptions are thrown that should have been caught
but are not.
Comment 9 Philipe Mulet CLA 2005-05-19 13:14:49 EDT
We provide warnings for boxing/unboxing operation. In order to detect this
special scenario, I am guessing this should be bundled with null reference
analysis which we'd like to consider in the future.
Would you mind opening a separate defect about this ? So we can look at it in
the future ?
Comment 10 Luke Hutchison CLA 2005-05-20 01:56:56 EDT
Created bug 96063 as requested.  Je vous remercie.