Live data from Hacker News

Why nullable types?

medium.com

51–60 of 119 posts

Re: Why nullable types?

#51
post #3

> it is entirely possible to live without null, and languages like Rust do. It seems as though there is this common misconception that Rust does not have a concept of null. Rust does have null pointers [1]! The reason many people do not see null often is because working with and dereferencing raw pointers is an unsafe operation 1: https://doc.rust-lang.org/std/ptr/fn.null.html

> It seems as though there is this common misconception that Rust does not have a concept of null. I don't think that's quite relevant, though. Rust doesn't have a concept of nulls like like Java, Javascript, Python, etc do in which just about any variable might contain a value or null. Rust certainly doesn't have that.

I would not say that it is not relevant. Raw pointers are a fundamental part of the language. It is just that Rust abstracts over them so that many users do not have to worry about them.

I see your point though.

Re: Why nullable types?

#52

>There are two main solutions: Use an option or maybe type or Use a nullable type I don't get it. These are literally all exactly the same thing, all slightly varying in ergonomics and compiler support. They may differ slightly but to call them two different categories of solution is just creating a false dichotomy for yourself. > However, the type system is a little more flexible than with option types. The type sys…

No, this is valid in languages with nullable types: String s = null; But this is not legal in languages without them: String s = None; In those languages, in order to have a value of None, it must be of type Option (or whatever the syntax is), and in order to get a value of type String, you must assert its presence. This is a fundamental difference with many ramifications. It really isn't just "the same but with bett…

    String s = null;
That's not possible with nullable types. The whole point of nullable types is to mark types that can be null. So this is possible:

    String? s = null;
But now it's not much different than this:

    Option s = None;
My point is that these are fundamentally the same thing. The only difference is syntax, ergonomics, and compiler support.

Re: Why nullable types?

#53
post #39

>There are two main solutions: Use an option or maybe type or Use a nullable type I don't get it. These are literally all exactly the same thing, all slightly varying in ergonomics and compiler support. They may differ slightly but to call them two different categories of solution is just creating a false dichotomy for yourself. > However, the type system is a little more flexible than with option types. The type sys…

They're not the same. The difference is that what the article calls "nullable types" are based on commutative unions, while option types are based on non-commutative unions. In haskell, Either a (Either b c) is distinct from Either (Either a b) c. In typescript, a | (b | c) is identical to (a | b) | c. And further, x | x is identical to x in typescript. The upshot is that Haskell (using Either instead of Maybe for cl…

> So nullable types are less powerful than option types.

They are differently powerful. Option types nest, while nullable types flatten. But nullable types subtype while option types do not.

Otherwise, I think your comment is an excellent summary of the differences.

Re: Why nullable types?

#54

>There are two main solutions: Use an option or maybe type or Use a nullable type I don't get it. These are literally all exactly the same thing, all slightly varying in ergonomics and compiler support. They may differ slightly but to call them two different categories of solution is just creating a false dichotomy for yourself. > However, the type system is a little more flexible than with option types. The type sys…

No, this is valid in languages with nullable types: String s = null; But this is not legal in languages without them: String s = None; In those languages, in order to have a value of None, it must be of type Option (or whatever the syntax is), and in order to get a value of type String, you must assert its presence. This is a fundamental difference with many ramifications. It really isn't just "the same but with bett…

    String s = null;
This is a compile error in Dart now. We added nullable types in order to make all other types not nullable. So unless you explicitly opt in to nullability by putting "?" on the type, you can a type that does not permit null.

Re: Why nullable types?

#55

I guess a third option would be to use an "Option" but with much more syntactic sugar. So, rather than calling func(some(3)), you'd just call func(3) and the compiler would automatically wrap it up. Func would be declared this way: def func(int?) to indicate that it's an optional type. IMO you get the best of both world. And then, in many places in the code, you'd have to do "r?.foo()" if r is an Option type. It's di…

> So, rather than calling func(some(3)), you'd just call func(3) and the compiler would automatically wrap it up.

You can do implicit conversions and that helps somewhat, but it's not quite the same as actual subtyping. In many cases, there's no natural or efficient way to insert that conversion so you still run into restrictions. For example, in a language with nullable types you can write:

    int sumPresentValues(Iterable values) {
      var result = 0;
      for (var value in values) if (value != null) result += value;
      return result;
    }

    main() {
      Iterable values = [1, 2, 3, 4];
      print(sumPresentValues(values)); // 
The marked line is passing an `Iterable` to a function expecting an `Iterable`. That works because `int` is an actual subtype of `int?` with no conversion required. With a boxing step, you'd need to somehow wrap the entire collection in one that does the conversion.

Re: Why nullable types?

#56
post #9

I think dart made the wrong choice here, but I've never used the language personally or professionally. I give the author the benefit of the doubt but Optionals are so much more powerful than what this article covers. You can map, filter, reduce, chain, compose functions that all work with optionals, and lift functions that work on numbers (or any other type) to be functions that work on Optional but none of that is…

> You can map, filter, reduce, chain, compose functions that all work with optionals, and lift functions that work on numbers (or any other type) to be functions that work on Optional but none of that is even mentioned in this piece (likely cause then its harder to justify picking nullable types instead)

Maybe I'm missing something, but I don't see how that's special to option types. Here's a set of extension methods in Dart that provide the operations you describe:

    extension NullableExtensions on T? {
      R? map(R Function(T) transform) => this == null ? null : transform(this);

      T? filter(bool Function(T) predicate) {
        if (this == null) return null;
        if (predicate(this)) return this;
        return null;
      }
    }

    extension FunctionExtensions on R Function(T) {
      R? Function(T?) lift() => (T? param) => param == null ? null : this(param);
    }

    extension NullableIterableExtensions on Iterable {
      Iterable map(R Function(T) transform) =>
          this.map((e) => e == null ? null : transform(e));

      Iterable filter(bool Function(T) predicate) =>
          where((e) => e == null || predicate(e));
    }
Chaining has built-in syntax:

    int? maybeInt = ...
    print(maybeInt?.isEven.toString());
I'm not sure what you mean by "compose".

Of course, this is not entirely as expressive as option types because of the inability to nest, but the article is pretty clear that nesting is the major advantage of option types.

Re: Why nullable types?

#57
post #30

>There are two main solutions: Use an option or maybe type or Use a nullable type I don't get it. These are literally all exactly the same thing, all slightly varying in ergonomics and compiler support. They may differ slightly but to call them two different categories of solution is just creating a false dichotomy for yourself. > However, the type system is a little more flexible than with option types. The type sys…

This comment is misleading. They may appear to be the same but they are not because in certain languages (like Rust) you are forced to handle the `Option` case when a value is `None` which guides a programmer's thinking in the direction of what to do in that situation. Without these higher level types runtime null pointer exceptions are very common, using `Option` or `Maybe` creates a situation where these sorts of e…

> They may appear to be the same but they are not because in certain languages (like Rust) you are forced to handle the `Option` case when a value is `None` which guides a programmer's thinking in the direction of what to do in that situation.

Languages with nullable types are equally strict:

    int? maybeInt;
    maybeInt + 3; // 

Re: Why nullable types?

#58
post #24

I agree that union-typed null was the best solution for Dart, but I think many of the article's criticisms of option types aren't good. > We can’t perform arithmetic on an Option any more than we could on a List . Why not? One sensible definition is Some(x) + Some(y) = Some(x + y) _ + _ = None() > In fact, with Dart, we’ve found that most existing code is already statically null safe This is a very good reason to use…

> Different people will assign different meanings to null, and it's a real headache when trying to write generic code.

This is a legitimate concern, but my experience has been that it is a surprisingly rare problem in practice. We software engineers are trained to believe that any system that supports 1 of something is obligated to generalize and support N of them. But you'd be surprised how far just one sentinel value gets you.

I mean, one of the key observations underpinning having nullable (and thus non-nullable) types is that most places in your code need zero of these sentinel values. Most type, around 90% the last time I tried to count, don't permit null at all, so needing two distinct absent values is quite rare.

Re: Why nullable types?

#59

Earlier quoted context omitted.

> You can map, filter, reduce, chain, compose functions that all work with optionals Maybe they didn't mention it because both approaches can do that, or maybe I'm misunderstanding?

The difference I see is, when you work with a nullable type, each function has to do the check so const add3 = (val) => val ? val + 3 : null; const multiplyBy10 = (val) => val ? val * 10 : null So the argument type goes from being val to val? where the calling code doesn't necessarily have type safety since this argument is now optional (it can be a number or null and either is acceptable) instead of the following (w…

You could define operations on nullable types to allow this in Dart, like:

    extension NullableNumExtensions on num? {
      num? operator +(num? other) {
        if (this != null && other != null) return this + other;
        return null;
      }
    }

    main() {
      num? i, j;
      print(i + j);
    }
For method calls, we have a null-safe method call syntax that automatically lifts the operation to give you a nullable result:

    int? i;
    var b = i?.isEven; // b has type null?
We could have made all operations implicitly do this lifting, but our experience is that this isn't what users want. They want to know as early in their code when an operation on a potentially-absent value is attempted and reconcile right there what behavior they want.

Re: Why nullable types?

#60
post #41

If we look at set theory the NULL set is a valid set. The problem with NULL is often it's just treated as zero or if passed to a language that does not have NULL it's pretty often to just treat it as Zero. This bit equivalence between zero and NULL zero is often what you see lead to problems. It's why for instance with GPS coordinates NULL island exists. However, errors aside NULL is a perfectly logical value to enco…

> NULL is a perfectly logical value to encounter or need.

Great! Assign to it the type Null.

This is legal:

    Null myNull = null;
Make this illegal:

    Integer i = null;
Post reply on HN