Following code
import scala.language.implicitConversions
object myObj {
implicit def nullToInt(x: Null) = 0
def main(args: Array[String]): Unit = {
val x = 1 + null
val y = 1 + nullToInt(null)
println(x + " " + y)
}
}
gives below result
1null 1
I was expecting both vals to be Int and equal to 1.
Apparently first val is String and equals "1null".
Xprint:typer
shows that source code is translated into
package <empty> {
import scala.language.implicitConversions;
object myObj extends scala.AnyRef {
def <init>(): myObj.type = {
myObj.super.<init>();
()
};
implicit def nullToInt(x: Null): Int = 0;
def main(args: Array[String]): Unit = {
val x: String = 1.+(null);
val y: Int = 1.+(myObj.this.nullToInt(null));
scala.Predef.println(x.+(" ").+(y))
}
}
}
There are no symbolic methods for int which accept null
scala> 10+null
res0: String = 10null
scala> 10*null
<console>:12: error: overloaded method value * with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int
cannot be applied to (Null)
10*null
^
scala> 10-null
<console>:12: error: overloaded method value - with alternatives:
(x: Double)Double <and>
(x: Float)Float <and>
(x: Long)Long <and>
(x: Int)Int <and>
(x: Char)Int <and>
(x: Short)Int <and>
(x: Byte)Int
cannot be applied to (Null)
10-null
^
I assume both "1" and "null" were converted into String instead of applying implicit nullToInt. Can someone explain how compiler came up with that? What logic/workflow was used?
And another question is whether there is a way to enable implcit nullToInt?
PS. I'm not talking about best practices here. Feel free to consider a question as a matter of academic interest.
An implicit conversion sequence is the sequence of conversions required to convert an argument in a function call to the type of the corresponding parameter in a function declaration. The compiler tries to determine an implicit conversion sequence for each argument.
Implicit conversions: No special syntax is required because the conversion always succeeds and no data will be lost. Examples include conversions from smaller to larger integral types, and conversions from derived classes to base classes.
Implicit conversions allow the compiler to treat values of a type as values of another type. There's at least one set of scenarios in which this is unambiguously bad: non-total conversions. That is, converting an A to a B when there exists A s for which this conversion is impossible.
I'll try to answer my own question.
The subject is a bit misleading and in fact no implicit conversions are applied to the expression for val x at all. Null
is a subtype of String
and Int has method abstract def +(x: String): String
so it can be applied to Null as well.
This is also confirmed by the output of Xprint:typer
because it's supposed to show all implicit conversions and apparently it does not show anything for expression for x.
And answering questions "whether there is a way to enable implcit nullToInt", the only way to enable it is to specify explicitly in this case, because compiler will not consider using any implicits when code is successfully compiled without them.
So, what @AndreyTyukin says is right, mechanically I think there is more to it. There are two things that are going on as to why.
Any
is decorated with an implicit
in the Predef
, see the following:
implicit final class any2stringadd[A] extends AnyVal
As you can see, any2stringadd
is what is responsible for the +
and you can see the signature here:
def +(other: String): String
Correction: There are no implicit conversions
, it was even simpler than that
Predef
and any2stringadd
which is indeed at play is the followingimplicit final class any2stringadd[A](private val self: A) extends AnyVal {
def +(other: String): String = String.valueOf(self) + other
}
String.valueOf
of 1
will return a String
of 1
. In Java (and verify with a jshell), a String
of 1
added to null
will become 1null
.
jshell> "1" + null
$1 ==> "1null"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With