1

Why does the following compile? I understand that AnyVal instances correspond to things in the underlying host system that cannot be constructed, and that Null is a subtype of all reference types but not of value types. I have an AnyVal type Boolean I give to safeMapDifferent, but don't see how it can satisfy this constraint of U >: Null.

object MyMainScala extends App { implicit class RichObject[T](o: T) { def safeMap[U](method: T => U)(implicit ev: Null <:< U): U = Option(o).flatMap(result => Option(method(result))).orNull def safeMapDifferent[U >: Null](method: T => U): U = Option(o).flatMap(result => Option(method(result))).orNull } override def main(args: Array[String]): Unit = { val testSubject = new Object() { def scalaBoolean: Boolean = ??? } // println(testSubject.safeMap(_.scalaBoolean)) // If not commented, this will fail to compile as I expect. println(testSubject.safeMapDifferent(_.scalaBoolean).getClass) // Why does it compile? } } 

1 Answer 1

5

Its because of Autoboxing. If you see in predef.scala, you will see bunch of implicit conversion methods that convert scala AnyVal to Java.

 /** @group conversions-anyval-to-java */ implicit def boolean2Boolean(x: Boolean): java.lang.Boolean = x.asInstanceOf[java.lang.Boolean] 

When you invoke your print method, println(testSubject.safeMapDifferent(_.scalaBoolean).getClass), you are providing T => U value i.e. _.scalaBoolean which takes testSubject as parameter which satisfy T type parameter and returns Boolean which does not satisfy U >: Null. Upon getting this error, instead of throwing exception, the compiler looks for implicit methods which can convert Boolean into expected U >: Null type and it found boolean2Boolean in predef.scala which satisfy this constraint because java.land.Boolean is a reference type. Hence, compile execute the code correctly.

def foo[U >: Null](o : U) = println(o) foo(true) // compile correctly. foo[java.lang.Boolean](true) //compile correctly, because true is implicitly converted to java Boolean and java.lang.Boolean is reference type and superType of scala.Null. 

To avoid this, you must statically provide type parameter: foo[Boolean](true) //won't compile.

Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.