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

Support non-nullable types. #22

Open
DartBot opened this Issue Oct 10, 2011 · 21 comments

Comments

Projects
None yet
8 participants
@DartBot
Copy link

DartBot commented Oct 10, 2011

This issue was originally filed by cflew...@gmail.com


Short version: Null pointers are a really good way to mess up a program at runtime, and I'd like the Dart team to reevaluate whether they're absolutely required.

Slightly longer version: I would say the #­1 cause of issues in my programs (excluding logical errors/requirements errors) are NPEs. Having a language support NPE removal, be it via some clever compiler warning or simply removing null altogether, would be wonderful. I'm personally partial to Scala's method of null removal, but I'm sure PL gurus like yourselves have seen many others.

Dart has a stated goal of avoiding the creation of programs that "are difficult to debug or maintain." NPEs are a huge pain point in this regard. I'd be really happy if the Dart team reevaluated whether they are absolutely required to achieve the other aims.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by johnle...@google.com


Issue #24 has been merged into this issue.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by rchandia@google.com


some input from the author of null references:

http://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by ivan.the.ter...@gmail.com


I have to agree. From reading through the tutorial, it sounds like Dart is handling null even worse than most languages. (Even numbers might be null?!)

Given that types are optional, it would make sense to allow null when the type is unspecified (var or dynamic return), but if the user (programmer) is explicitly saying that this variable is an int, why should the type checker assume that null is ok?

Null can be useful, but if I am choosing to explicitly declare a type, please let me also explicitly say whether it is allowed to be null. I personally would prefer option types, but given that this language seems to be trying to be similar to C++/Java/Python, perhaps declaring things nullable would be better. For example, if you write "nullable int n = 42", then "n = null" would be allowed.

Another option would be to explicitly annotate variables as not null, like "not_null int n = 42", but IMHO, the only advantage to that would be that it wouldn't break existing code, and given that this is a new language, that's not a very good reason.

http://qconlondon.com/london-2009/presentation/Null+References:+The+Billion+Dollar+Mistake
http://se.ethz.ch/~meyer/publications/hoare/void-safety.pdf
https://secure.wikimedia.org/wikipedia/en/wiki/Nullable

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by waqn...@gmail.com


I don't think it is possible to completely forbid null-references in a language that allows dynamic types.

However, on page 73 of the Dart language specification draft, the question is asked "Should we do something with respect to non-nullable types?" and my answer is YES, PLEASE, I'M BEGGING YOU.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by jat@google.com


There was discussion of allowing int? foo to mean that foo might be nullable, and just int foo would mean it wasn't. However, there were some complications, particularly with the idea of types being optional -- ie, removing a non-nullable type annotation could change the behavior of the program.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by waqner...@gmail.com


May I ask what these complications look like?
When would removing a non-nullable type change the behavior of the program, and how exactly would the behavior be different?

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by leozc.l...@gmail.com


I would suggest to borrow C# concept which separate value type from object and only object can be null.

If we want value type (like int) be null we can use a constructor and wrap it as a object nullable<int>.

A plain int can be null is usually a disaster for dev..

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 10, 2011

This comment was originally written by ladicek@gmail.com


Nullable types should definitely be added. At least in the expected form where checker would warn you while prod env would let you assign nulls anyway.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by jat@google.com


One example of changing behavior:

int foo = null; // throws NPE
int? foo = null // ok

If you strip off the types, you change the behavior of the program.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by clun...@purelunacy.com


Nullable types need to exist as long as default constraints are identified for the type. Much like C# default(t) with a user pragma like declaration . This would allow for ease of intrinsic types and nullable types based on conditions.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by waqn...@gmail.com


@JaT I don't understand.
Why would a non-nullable
int foo = null;
throw an exception? I thought the type checker only produces compile-time warnings.

A type warning would be perfectly adequate in this case, and not change the behavior of the program if the type is removed. Or am I missing something?

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by jat@google.com


So what happens when you dereference a null pointer (that was declared to be non-nullable) at runtime? I don't see how you usefully continue -- the program is broken, and you are better off failing at the point you assign the null pointer to it.

You can do things like require such variables to be initialized and forbid assignment of a null literal, but in general you are not going to be able to tell if the execution of the program would lead to assigning a null to a variable -- it may even reference external things, such as a server or the DOM, that the compiler can't know the behavior of. Even if you require that such functions be declared as "Foo?" and require explicit null checks when assigning to a "Foo", the server might still return a null when it was declared not to.

@dgrove

This comment has been minimized.

Copy link
Member

dgrove commented Oct 11, 2011

Removed Type-Defect label.
Added Type-Enhancement, Area-Language labels.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by drfibonacci@google.com


Added Triaged label.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by ivan.the.ter...@gmail.com


jat: I thought I read that when running in production mode any type errors were supposed to be ignored, so types don't affect the behavior of the program. When running with checking enabled they do, but that is regardless of whether you allow non-nullable types.

For example:
int foo = 'World'; // throws something? (not in production at least)
var foo = 'World';

The same applies to your argument wrt a server or the DOM. If it can return a null when it was declared not to, couldn't it just as easily return a string when it was declared not to?

If you are really worried that making types non-nullable by default would result in question marks all over the place, could you at least support explicitly marking a variable as non-nullable? That would be completely backwards compatible, but having it sooner would mean library writers would be more likely to use it, which would benefit everyone.

I still think explicitly marking nullable ones is better, because that is when you should be thinking about the fact that it might be null, and the presence of a marker tends to be a better reminder for people than it's absence.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by michaels...@gmail.com


Agreed. For a given type T, a variable declared to have type "T" should not be allowed to be null, whereas a variable declared to have type "T?" should be allowed to be null.

I don't see why changing the declaration is not allowed to change the behavior of the program, though. Changing a function from allowing null to not allowing null is always a backwards-incompatible change, and I think -- in a lot of the use cases -- the function would not have actually supported null, to begin with. The use of the annotation just makes this lack of support more well documented and exposes the error sooner.

@munificent

This comment has been minimized.

Copy link
Member

munificent commented Oct 11, 2011

I don't see why changing the declaration is not allowed to change the behavior of the program, though.

Well, that is sort of the fundamental idea behind optional types: they're optional. You're of course free to disagree with that concept, but that probably means no amount of feature changes will make Dart into the kind of language you want.

Changing a function from allowing null to not allowing null is always a backwards-incompatible change, and I think

Changing the body of a function to something that no longer will work if you pass null is definitely a backwards-incompatible change. That's different, though, than changing the type annotation of what the function expects.

The use of the annotation just makes this lack of support more well documented and exposes the error sooner.

Right, that's what's great about type annotations (or annotations in general): they give a nice user-visible distillation of what the API expects. But you can get that benefit without the type annotation enforcing what it communicates. That's the model of optional types: it will try to tell you that it thinks you're doing something wrong, but it won't totally prevent you from doing it. You're presumed to be smarter than the type checker, so in the case of a disagreement, it will submit to your will.

@DartBot

This comment has been minimized.

Copy link

DartBot commented Oct 11, 2011

This comment was originally written by michaels...@gmail.com


Ok, I'm afraid I just don't get it. My understanding of optional types is that you don't need to declare the types, but you can if you want to. However, where does it say that declaring the types has no effects?

If declaration types have no effects, then what the hell is the point in adding them back? Isn't enforcing type-safety (which would include nullability), a motivation for developers to add back types? If types have no purpose other than documentation, what's the point?

@munificent

This comment has been minimized.

Copy link
Member

munificent commented Oct 11, 2011

However, where does it say that declaring the types has no effects?

Gilad can explain it better than I can: http://www.dartlang.org/articles/optional-types/

then what the hell is the point in adding them back?

They do a few things for you:

  1. They document the expected types of a function for other programmers looking at your code.
  2. You can run Dart code in "checked" mode. When you do, all type annotations will be dynamically checked and report an error if the types don't match. (By "dynamically" I mean, at runtime, when you assign to a variable with a declared type, it will check then.)
  3. Tools (such as the Dart compiler) may also opt to use those type annotations to perform static type checking and report static type errors that they find.

I think those cover most of what you want from types (performance is the other piece, but I think Dart can be plenty fast without that), but note that none of them affect the runtime behavior in unchecked mode. So you can get what you want from types, but you aren't required to satisfy the type system in order to run your code.

@sethladd

This comment has been minimized.

Copy link
Member

sethladd commented Jul 28, 2015

FYI a relevant DEP is dart-lang/dart_enhancement_proposals#30

@munificent munificent removed the C12 label Jun 20, 2018

@hereisderek

This comment has been minimized.

Copy link

hereisderek commented Sep 7, 2018

I'd really love to see this get implemented, or better yet, kotlin/swift style optional variable support

@lrhn lrhn added core-a and removed p2-medium labels Dec 6, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment