possible bug in conversion of java.lang.Double to Option[Double]

1,358 views
Skip to first unread message

Todd O'Bryan

unread,
Apr 18, 2013, 10:13:24 AM4/18/13
to scala-user
I'm guessing that this is not intended behavior. Is there a bug already posted about this? (I've tried it in 2.9.2, but haven't had a chance in 2.10, yet.)

scala> val d1: java.lang.Double = 1.0
d1: java.lang.Double = 1.0

scala> val d2: Double = d1
d2: Double = 1.0

scala> val dn: java.lang.Double = null
dn: java.lang.Double = null

scala> val dn2: Option[Double] = Option(dn)
java.lang.NullPointerException
        at scala.Predef$.Double2double(Predef.scala:363)
        at .<init>(<console>:8)
        at .<clinit>(<console>)
        at .<init>(<console>:11)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:704)
        at scala.tools.nsc.interpreter.IMain$Request$$anonfun$14.apply(IMain.scala:920)
        at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
        at scala.tools.nsc.io.package$$anon$2.run(package.scala:25)
        at java.lang.Thread.run(Thread.java:662)


scala> Option(dn)
res0: Option[java.lang.Double] = None

scala> Option(dn).asInstanceOf[Option[Double]]
res1: Option[Double] = None

The same thing happens with a conversion from java.lang.Integer to Option[Int]. The obvious workaround is to write

if (d == null) None else Some(d)

instead of 

Option(d)

but it seems like you shouldn't need to do that.

Todd

Andrzej Giniewicz

unread,
Apr 18, 2013, 10:37:02 AM4/18/13
to Todd O'Bryan, scala-user
On Thu, Apr 18, 2013 at 4:13 PM, Todd O'Bryan <toddo...@gmail.com> wrote:
> I'm guessing that this is not intended behavior. Is there a bug already
> posted about this? (I've tried it in 2.9.2, but haven't had a chance in
> 2.10, yet.)

This:

scala> val dn2: Option[java.lang.Double] = Option(dn)
dn2: Option[Double] = None

works, but this does not:

scala> val dn2: Option[scala.Double] = Option(dn)

when you write Double, you get scala.Double not java.lang.Double.
Although I think you can unbox the type by hand:

scala> val dn2: Option[scala.Double] = Option(scala.Double.unbox(dn))
dn2: Option[Double] = None

or shorter

scala> val dn2: Option[Double] = Option(Double.unbox(dn))
dn2: Option[Double] = None

which seems to be better alternative than if (d == null) ..., yet
still I'm not experienced enough to tell why you have to do it by hand
in this case.

pagoda_5b

unread,
Apr 18, 2013, 10:42:15 AM4/18/13
to scala...@googlegroups.com
2.10 still shows the same behavior, I agree that this should be an unwanted issue.

The conversion problem comes from the fact that we're asking the compiler to convert the java.lang.Double to a scala.Double, needed as parameter for Option.apply[A](x: A), and this happens before the apply method is even called, to satisfy the types.

This is tricky because the problem is not related to the Option operations at all, for which it could make sense to pass a null value for Option "translation".
Any method expecting a scala.Double (or Int or whatever) will get the NPE if you pass a null java.lang.Double, because the Predef conversion from java numeric wrappers to the scala numeric types doesn't check for null input...

Andrzej's work-around seems a nice choice to me

Bye,
Ivano

Johannes Rudolph

unread,
Apr 18, 2013, 10:49:57 AM4/18/13
to Andrzej Giniewicz, Todd O'Bryan, scala-user
On Thu, Apr 18, 2013 at 4:37 PM, Andrzej Giniewicz <ggi...@gmail.com> wrote:
> val dn2: Option[Double] = Option(Double.unbox(dn))

And now please explain, why that works :)

As a bonus, guess what this prints:

val unboxed = Double.unbox(dn)
val dn3: Option[Double] = Option(unboxed)
println(dn3)


--
Johannes

-----------------------------------------------
Johannes Rudolph
http://virtual-void.net

Andrzej Giniewicz

unread,
Apr 18, 2013, 11:18:38 AM4/18/13
to Johannes Rudolph, Todd O'Bryan, scala-user
On Thu, Apr 18, 2013 at 4:49 PM, Johannes Rudolph
<johannes...@googlemail.com> wrote:
> And now please explain, why that works :)

Hey, I don't think I can explain it so correct me if I'm wrong, but I
can give more examples:

scala> val x: Any = Double.unbox(dn)
x: Any = null

scala> x.asInstanceOf[Double]
res44: Double = 0.0

scala> val y: Double = Double.unbox(dn)
y: Double = 0.0

I believe that this is because null is instance of scala.Null, and
forcing type to be Double gives you this 0.0 somehow. Instead, I think
that when you use it inside Option(), which is polymorphic (it's
actually Option.apply that is Option.apply[A]), compliler magically
gets the correct type.

At least it seems to be something like it :)

Jason Zaugg

unread,
Apr 18, 2013, 6:06:19 PM4/18/13
to Todd O'Bryan, scala-user
On Thu, Apr 18, 2013 at 4:13 PM, Todd O'Bryan <toddo...@gmail.com> wrote:
I'm guessing that this is not intended behavior. Is there a bug already posted about this? (I've tried it in 2.9.2, but haven't had a chance in 2.10, yet.)

scala> val d1: java.lang.Double = 1.0
d1: java.lang.Double = 1.0

scala> val d2: Double = d1
d2: Double = 1.0

scala> val dn: java.lang.Double = null
dn: java.lang.Double = null

scala> val dn2: Option[Double] = Option(dn)
java.lang.NullPointerException

Seems like a great advertisement for Scala 2.10.1 and -Xlint

scala-hash v2.10.1 -Xlint
[info] v2.10.1 => /Users/jason/usr/scala-v2.10.1-0-g77b864e
Welcome to Scala version 2.10.1-20130302-092018-33e32179fd (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_37).
Type in expressions to have them evaluated.
Type :help for more information.

scala> val dn: java.lang.Double = null
dn: Double = null

scala>  Option(dn): Option[Double]
<console>:9: warning: Suspicious application of an implicit view (scala.this.Predef.Double2double) in the argument to Option.apply.
               Option(dn): Option[Double]
                     ^
java.lang.NullPointerException
at scala.Predef$.Double2double(Predef.scala:395)


-jason 

Som Snytt

unread,
Apr 18, 2013, 7:09:07 PM4/18/13
to Jason Zaugg, Todd O'Bryan, scala-user

I'm wearing my "-Xlint would have told you not to do that" t-shirt right now!

http://code.google.com/p/dynamic-scala/source/detail?r=8068e1208466ab17af40c2670230ba5ac9704e0c

However, there seems to be an earlier reference on the javac side:

"If you had actually done as the compiler suggested, and recompiled with -Xlint, it would have told you exactly what needed to be changed."

But that's not as pithy.

https://forums.oracle.com/forums/thread.jspa?threadID=1247779



--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.
 
 

Todd O'Bryan

unread,
Apr 18, 2013, 7:59:24 PM4/18/13
to Johannes Rudolph, Andrzej Giniewicz, scala-user
OK, this is a problem. If not for the language, then at least for my brain which has just exploded.

val dn: java.lang.Double = null
val do: Option[Double] = Option(Double.unbox(dn))  // do is now None
val unboxed = Double.unbox(dn)
val do2: Option[Double] = Option(unboxed) // do2 in now Some(0.0)

There is no reason I can think of that this should violate referential transparency and force you to use some kind of non-substitution model of evaluation. If Double.unbox(null) results in 0.0, how can Double.unbox(null).asInstanceOf[Any] result in null? (Which, by the way, is what happens...)

Todd

Simon Ochsenreither

unread,
Apr 19, 2013, 8:49:21 AM4/19/13
to scala...@googlegroups.com, Jason Zaugg, Todd O'Bryan
Slightly related:

Option(null.asInstanceOf[Boolean])

should return Some(false), but results in None.
Reply all
Reply to author
Forward
0 new messages