8

When using the new Scala 3's flag -Yexplicit-nulls, every Java code which doesn't have explicit non-null annotations is treated as nullable, thus every Java method not returning a primitive type T effectively returns T | Null.

Problem: In Scala, String is just an alias for java.lang.String. And because core Java doesn't contain any annotations about the nullability, Scala 3 treats the return types of String methods as nullable.

Example: (tried via both Scala REPL / sbt console, and with Gradle)

scala> val bla: String = null // check whether the compiler option is turned on
-- Error:
1 |val bla: String = null
  |                  ^^^^
  |                  Found:    Null
  |                  Required: String
scala> val bla: String = "hey"
val bla: String = hey
scala> bla.split("e")
val res0: Array[String | Null] | Null = Array(h, y)

The return type Array[String | Null] | Null is completely insane. The contract of the split method is obviously given as it always returns an array and that array always contains at least one string (and none of the strings is null).

Is this really the sad reality, or am I doing something wrong?

To make the above work, I would always have to write:

"hey".split("e").nn.map(_.nn) // this would finally give me just Array[String]
  • Interestingly, this is somewhat mentioned in the Dotty elaboration about this topic: https://gist.github.com/abeln/9f79774bac111d99b3ae2cb9016a33e6#improving-precision or https://uwspace.uwaterloo.ca/bitstream/handle/10012/15364/NietoRodriguez_Abel.pdf?sequence=3&isAllowed=y But it doesn't seem to me that it would work like that in Scala 3.1... – Ota Hauptmann Jan 17 '22 at 22:17
  • The "Waterloo thesis" also mentions further flags which could turn on some external annotations of the Java methods, but it doesn't seem to me that Scala 3.1 would accept that parameter... `bad option '-Yjava-interop-checker-framework' was ignored` – Ota Hauptmann Jan 17 '22 at 22:36
  • you can just import unsafenulls when needed : https://dotty.epfl.ch/docs/reference/other-new-features/explicit-nulls.html#unsafenulls – volia17 Jan 18 '22 at 14:39
  • 1
    My point is that I don’t want to use unsafeNulls with ELEMENTARY String operations. Should I create a block with unsafeNulls for every string operation? I definitely don’t want unsafeNulls in whole file. I’d somehow accept the fact that using Java code automatically causes everything being nullable even though the contracts say otherwise, but again: String is somehow pronounced as Scala’s own. Yes, internally it’s an alias to Java string, but it’s a first-class citizen. – Ota Hauptmann Feb 01 '22 at 23:19
  • It would be nice to be able to list somewhere else methods for which possible nulls can be ignored and have the compiler act based on that. – user Feb 02 '22 at 15:00

2 Answers2

5

I have found a bug report talking about practically the same thing I was originally asking here. It seems the Dotty/Scala3 team considers this as "not a bug".

There was a suggestion to use unsafeNulls flag. Which is more of a "let's disable the feature we've just enabled".

1

Here is an experiment language feature, unsafeJavaReturn, which assumes Java methods don't return nullable values in explicit nulls

https://github.com/lampepfl/dotty/pull/15096

This is less aggressive than unsafeNulls, since it only affects Java interop in a certain scope.

yzhao
  • 11
  • 1