Skip to content

Clarify what methods are on Null and bottom #28430

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
leafpetersen opened this issue Jan 18, 2017 · 6 comments
Closed

Clarify what methods are on Null and bottom #28430

leafpetersen opened this issue Jan 18, 2017 · 6 comments
Assignees
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). P1 A high priority bug; for example, a single project is unusable or has many test failures
Milestone

Comments

@leafpetersen
Copy link
Member

Issue #28024 tracks moving Null to the bottom of the type hierarchy. We need to clarify in the specification what methods are available on the Null type (and the bottom type if the answer is different).

The natural answer based on a substitutability principle is that all methods should be allowed to be called on Null, and this has been the de facto interpretation of the current Dart spec for bottom (even though it does not make this explicit).

List<int> l = new List<Null>();
l[0].abs(); 

A substitution principle suggests that replacing l with its definition should still be well-typed.

This is not definitive though. We can certainly choose to provide stronger checking, and it's not clear that there are practical reasons not to. There are certainly good reasons to do the stronger checking. The use of Future<Null> to indicate a Future whose value should not be used is very suggestive. We would lose substantial static checking if all uses of the result of a Future<Null> became valid.

Future<Null> dontUseMyResult f = ...;
dontUseMyResult.then((n) => n.abs()); // No warnings?

cc @floitschG @lrhn @eernstg @munificent @scheglov @bwilkerson @stereotype441

@leafpetersen leafpetersen added the area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). label Jan 18, 2017
@leafpetersen leafpetersen added this to the 1.22 milestone Jan 18, 2017
@leafpetersen
Copy link
Member Author

Assigning to @lrhn since you wrote up the initial spec - please assign back to me if you'd prefer me to take this.

@leafpetersen
Copy link
Member Author

For what it's worth, I think my preference is to treat Null as having nothing but the Object methods.

When and if we add Nothing (aka true non-nullable bottom) we should treat this as having all methods, since that matches the expected use cases (throw and functions which do not return).

We could consider in the meantime treating bottom (that is, the static type of throw in the current spec draft) as also having all methods. Essentially then for the meantime bottom and Null become variants on a common bottom type, much as dynamic and Object are equivalent types with different error and warning behavior.

@lrhn
Copy link
Member

lrhn commented Jan 18, 2017

The idea behind the spec documentation (for Dart 1) is that Null is only extending Object. It has no other methods (which is clear since it's effectively declared as class Null { }). It's not documented in the spec (well, I actually think it is mentioned, but it doesn't need to be) - the Null class declaration is in the platform libraries just as the int class.

For subtyping and assignability, Null is considered a subtype of any type, extended to type parameters and function return types in the predictable way, but it is not actually extending those types. It's a subtype by fiat, not by subclassing.

As for substitutability, nullability is inherently unsafe.
The

List<int> l = new List<Null>();
l[0].abs();

example looks unsafe because it is. But so is:

List<int> l = ... anything ...;
int x = l[0];
x.abs();

The x value can be null (at least until NNBD), whether l is actually a list of int or of Null. There is nothing new here. The type of x is nullable int and it might be null, and null doesn't have most of the members of int (never had, never will).

For:

Future<Null> dontUseMyResult f = ...;
dontUseMyResult.then((n) => n.abs()); // No warnings?

Definitely warnings. The static type of n is Null, Null does not have an abs member.

To be clear: Null is not bottom. It is Null, the subclass of only Object. We treat Null as a subtype of other types because we treat those other types as nullable types.

You can think of it as having nullable types in the language, and when you write int it means int? in most cases (the exception being is checks - and maybe type parameters, but then T is made nullable inmost cases when it's used).

Then we do unsafe things like calling abs on a nullable int without a warning, like we always have. Come NNBD, we'll probably stop doing that.

For the bottom type, I'm less definite. It exists - the spec mentions it and defines throw e to have it as the static type.
I'd say that bottom implements all interfaces, hypothetical or actual. That means that it has any member with any signature. That makes it assignable to any type and there should be no warning when accessing any member on it.
(I'd rather make it an error to use it, because I want to make all dead code errors, but that's not what we are doing so far).

@leafpetersen
Copy link
Member Author

Sounds good to me - I think this matches my preferences as well. Does this need to be clarified in the spec, or do you feel it's already implied? It wasn't clear to me reading through it that this was the intended interpretation, for what it's worth.

@munificent
Copy link
Member

SGTM too.

@mit-mit mit-mit added P1 A high priority bug; for example, a single project is unusable or has many test failures and removed P1 A high priority bug; for example, a single project is unusable or has many test failures labels Jan 19, 2017
@lrhn
Copy link
Member

lrhn commented Jan 19, 2017

I think the spec is correct wrt. the explanation above, but for clarity, I might add some commentary (https://codereview.chromium.org/2641873003/).
The spec already says:

The Null class declares no methods except those also declared by Object.

I don't want to elaborate too much on "nullable types" before we actually add them.

There might be a few other edge cases that we need to consider (like in an async function, a plain return; is only allowed if Future<Null> is assignable to the return type, but that's all future types now - probably safe, but a slight change from before, and probably to be changed again when we can write Future<void>).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-language Dart language related items (some items might be better tracked at github.com/dart-lang/language). P1 A high priority bug; for example, a single project is unusable or has many test failures
Projects
None yet
Development

No branches or pull requests

4 participants