I report it.

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
nullSimilar 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?
nullshould 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.
Most helpful comment
We could have a warning for
val x: 42 = null.asinstanceOf[42]as the value will never actually benull.