Scala 3 Explicit Nulls flag makes String operations quite unusable
Asked Answered
V

2

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]
Vitrescence answered 17/1, 2022 at 21:33 Comment(5)
Interestingly, this is somewhat mentioned in the Dotty elaboration about this topic: gist.github.com/abeln/… or uwspace.uwaterloo.ca/bitstream/handle/10012/15364/… But it doesn't seem to me that it would work like that in Scala 3.1... 🤔Vitrescence
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 ignoredVitrescence
you can just import unsafenulls when needed : dotty.epfl.ch/docs/reference/other-new-features/…Murton
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.Vitrescence
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.Orian
V
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".

Vitrescence answered 17/1, 2022 at 22:50 Comment(0)
C
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.

Cottonwood answered 4/5, 2022 at 18:29 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.