Make Null a subclass of AnyVal under -Yexplicit-nulls

We have AnyKind already so Null <: AnyKind could also be possible with not sub classing Any. But then I guess be need to allow values still to be of type Null

I am with @sjrd here. AnyVal is the obvious superclass of Null. null is a value, but not a reference (in the explicit-nulls model). All values that are not references are under AnyVal. The only things that are under Any bit not AnyVal nor AnyRef are universal traits that can be implemented by both value and reference classes.

1 Like

that’s a strong opinion.

is there a language with proper nulls (i.e. null pointers or references, not null-like stuff like empty optionals) that doesn’t define null as pointer or reference?

java calls null a reference and a value:
Chapter 4. Types, Values, and Variables .

The null reference is the only possible value of an expression of null type.

c# calls null a reference and a value:

The null keyword is a literal that represents a null reference, one that doesn’t refer to any object. null is the default value of reference-type variables. Ordinary value types can’t be null, except for nullable value types.

c# has explicit nullability mode. i haven’t dug deep if the definitions change under explicit nullability mode, but the null keyword page doesn’t mention such special cases.

there are two options: either the scala beginner should be prepared to deal with nulls or not:

  • if not, then simply redraw the diagram to make nulls less prominent and don’t elaborate on null
  • if yes, then lying that null is not a reference is counterproductive

imho the people that are most likely to run into null-related exceptions are beginners, irrespective whether nullness is explicit or not, so presenting some weird leaky abstractions to them won’t make them less affected by nulls. as i’ve written previously:

expand to see previous common type of example of unintentionally running into nulls

from my point of view, simplifications are sometimes more detrimental than helpful. good example is monads. when i was trying to grasp what’s the deal with monads, i’ve read many tutorials and most often they used some weird (sometimes even childish) analogies that didn’t help at all.

1 Like

Well, certainly in the regular case, null has multiple (diamond) inheritance with every reference class; Null is the bottom type of the hierarchy that has AnyRef as its top type.

With explicit nulls, whether or not you put null under AnyVal, you cut all those inheritance links. But it is an actual instantiable value, so you have to put it somewhere. You can match on it, so it has to be Matchable. The choices are really only (1) AnyVal or (2) its own thing directly under Matchable.

Then the question is that if you choose (1), do you swap the inheritance from AnyRef to AnyVal on explicit nulls, or is null always part of AnyVal and the only question is whether it also has diamond inheritance with AnyRef. So do you add a link, or only cut them?

Those are really the only two questions left. The issues about types lying will still be there; those are orthogonal. If String might be null, it should be typed as String | Null. Will it be, while genuinely always-instantiated string values are typed as String? The problem with the non-lie Null is that it is not a helpful truth. People rarely check nullness anyway, because the happy path is the one where you have ensured that the values have no nulls. But if that is intent, why not match the intent with the type?