Dotty: Mysterious Behavior of Literal Type

Created on 4 Feb 2018  Â·  16Comments  Â·  Source: lampepfl/dotty

I report it.

2018-02-04 21 05 37

nullability expert bug low

Most helpful comment

We could have a warning for val x: 42 = null.asinstanceOf[42] as the value will never actually be null.

All 16 comments

What would you expect to be happen here?

That's cool. Looks more like a feature than a bug to me. I guess throwing an Exception would also be an option.

It is as designed. When we have a reference to a literal value, the value of that type is used instead of the reference. It is kind of an inline optimization.

We could have a warning for val x: 42 = null.asinstanceOf[42] as the value will never actually be null.

Makes sense to me: doing an illegal cast produces unexpected results, though not an Exception as usual. Is there any documentation to update? Otherwise the issue can IMHO be closed.

If we use a def we do produce buggy code.

object Foo {
  def x: 42 = null.asInstanceOf[42]
  val y: 42 = null.asInstanceOf[42]
  def main(args: Array[String]): Unit = {
    println(x)
    println(y)
  }
}

prints

0
42

String literal types do not preserve null

Similar code with String literal type does not require asInstanceOf.

object StrLitNull{
  def main(a: Array[String]) = {
    val x: "constant" = null
    println(x)
  }
}

Or just println(null:"constant").

Output (dotty):

constant

Output (scalac):

null

The question is, is null a valid value of a string literal type?
I'd say yes, but it is optimized away like in the Int case above.

null should not be a valid value of type "constant". The code println(x:"constant") is corrrectly constant folded to println("constant") as the only inhabitant of the type "constant" is the value "constant".

Currently Null is a subtype of all references. Which lets us use null as a constant String. With the planed null safty this will not be the case and this will not be an issue anymore.

If this is about null safety, what do you think @liufengyun?

null should not be a valid value of type "constant"

Arguably. However the SIP committed decided otherwise, at least for Scala 2 ... all reference types, string literal types included, have null as an inhabitant.

Maybe this should be revised that if we change the way we handle null in the future. It would be much better to have to use "constant" | Null to avoid surprises.

I think it would actually be cool to be able to write val x: 42 and have it be automatically initialized.

The latest Dotty version gets 0. Inline happens as before. Both seem to be reasonable to me.

➜  dotty git:(safe-init) ✗ dotc -version
Dotty compiler version 0.10.0-RC1 -- Copyright 2002-2018, LAMP/EPFL

➜  dotty git:(safe-init) ✗ dotr
Starting dotty REPL...
scala> val x: 42 = null.asInstanceOf[42]
val x: Int(42) = 0

I don't think null-safety can help much here if programmers use asInstanceOf explicitly, which exploits/abuses feature of run-time platform.

cc @abeln .

The point of null safety would to not make null an instance of 42.

On the other hand casting can always produce wrong programs. But programs without casts should not have surprises.

By the way, null and string literal types make one more way of getting a value of Nothing,
which explicit nulls should easily solve.

trait A { def const:"A" }
trait B { def const:"B" }
object GetNothing {
  def check(n:Nothing) = println("Got nothing")
  def main(a: Array[String]) = {
    val nothing = (new A with B{override def const:Null = null}).const
    check(nothing)
  }
}

null.asInstanceOf defines the "default value".

scala> var x: 42 = _
var x: 42 = 0

I don't know if asking for a 42 should distinguish stable values, and maybe I should not witness the zero, the same way unboxing an Int will give me zero and not NPE.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

julienrf picture julienrf  Â·  3Comments

noti0na1 picture noti0na1  Â·  3Comments

ohze picture ohze  Â·  3Comments

odersky picture odersky  Â·  3Comments

travisbrown picture travisbrown  Â·  3Comments