Spec changes for explicit nulls - #26941
Conversation
In anticipation of a SIP for explicit nulls, these are proposed changes to the spec, for discussion. It remains as a TODO to make changes to 08-pattern-matching.md and 12-the-scala-standard-library.md.
| Types can be _concrete_ or _abstract_. | ||
| An abstract type ´T´ always has lower and upper bounds ´L´ and ´H´ such that ´L >: T´ and ´T <: H´. | ||
| A concrete type ´T´ is considered to have itself as both lower and upper bound. | ||
| A flexible type ´T?´ has lower bound `´T´ | scala.Null` and upper bound ´T´. |
There was a problem hiding this comment.
This is not the right place for this information. We're talking about two very different Ts. In the existing text, T refers to a type definition, as in type T <: .... But in the new sentence, it refers to a type usage.
Since you added them in the Internal Types, Flexible Types are their own dedicated thing (not a special abstract type member with bounds). In that case, you should:
- Add a new section "3.3.14 Flexible Types" to define what flexible types are, and notably say that
T?is only valid whenTis a proper type. - Add typing rules for
T? <: TandT | Null <: T?(which you already did).
If instead, flexible types are supposed to be a mere abstract type with weird bounds, then they shouldn't even appear in the type system. They should only be in the standard library section, under "Fundamental Type Aliases":
type <flexible-type>[T] >: T | Null <: TThere was a problem hiding this comment.
We'll need more offline discussion about which way to go for the spec.
One issue is that if the go with the applied type formulation, the following rule has to be disabled for flexible types:
Lines 1448 to 1457 in 1077009
- ´S = p.X[S_1, ..., S_n]´ and ´T = q.X[T_1, ..., T_n]´ are possibly parameterized type designators with ´n \geq 0´ and:
- `isSubPrefix(´p´, ´q´)`, and
- it is not the case that ´p.x´ and ´q.X´ are class type designators for different classes, and
- for each ´i \in \{ 1, ..., n \}´:
- the ´i´th type parameter of ´q.X´ is covariant and ´S_i <: T_i´ [^argisnotwildcard], or
- the ´i´th type parameter of ´q.X´ is contravariant and ´T_i <: S_i´ [^argisnotwildcard], or
- the ´i´th type parameter of ´q.X´ is invariant and:
- ´S_i´ and ´T_i´ are types and ´S_i =:= T_i´, or
- ´S_i´ is a type and ´T_i´ is a wildcard type argument of the form ´? >: L_2 <: H_2´ and ´L_2 <: S_i´ and ´S_i <: H_2´, or
- ´S_i´ is a wildcard type argument of the form ´? >: L_1 <: H_1´ and ´T_i´ is a wildcard type argument of the form ´? >: L_2 <: H_2´ and ´L_2 <: L_1´ and ´H_1 <: H_2´ (i.e., the ´S_i´ "interval" is contained in the ´T_i´ "interval").
Otherwise we get a mess of kind mismatches because FlexibleType[T] <: T.
The PR #26245 that represents flexible types as applied types disables a big pile of complicated logic for applied types when it sees a flexible type:
https://github.com/scala/scala3/pull/26245/changes#diff-c163f9660fb06bb487b0120921d06353fc52154ae1b3066f58da1c73ecd00914R1290
https://github.com/scala/scala3/pull/26245/changes#diff-c163f9660fb06bb487b0120921d06353fc52154ae1b3066f58da1c73ecd00914R1512
So if we go with the applied type formulation for the spec, we'll need to reflect that disabling in the spec.
Ideally what we'd really want is for a flexible type to have a type bounds as underlying, like an applied type does, but without all the messy complexity that comes from the application to type arguments (and how subtyping between applied types imposes new subtyping constraints between those arguments).
cc @odersky for your thoughts.
There was a problem hiding this comment.
The issue is more complicated than my comment suggests. A minimized example of what goes wrong without the exclusion of flexible types from the applied type handling is in the following test case in the PR:
https://github.com/scala/scala3/pull/26245/changes#diff-01ec396fd41d506d897e07f992e05506c89a349d4e5a22cba39a78dd5abf66b3
Co-authored-by: Sébastien Doeraene <sjrdoeraene@gmail.com>
In anticipation of a SIP for explicit nulls, these are proposed changes to the spec, for discussion.
It remains as a TODO to make changes to 08-pattern-matching.md and 12-the-scala-standard-library.md.
Have you relied on LLM-based tools in this contribution?
No
How was the solution tested?
Non-code change, no tests needed