Search code examples
scalaoperatorsstring-concatenation

Implicit conversions and null


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.


Solution

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