Live data from Hacker News

Why nullable types?

medium.com

41–50 of 119 posts

Re: Why nullable types?

#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 encounter or need.

Re: Why nullable types?

#42

>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 touch on why they're different a bit, but it's kinda subtle.

    foo(int? i) {
      if (i != null) {
        print(i + 1);
      }
    }
In that block, you can see that the compiler can understand that the null check on `i` means that it's safe to use `i` as an int within. Likewise, I can call `foo(int? i)` with `var something = 1`. `something` is an `int` and all `int`s are also `int?`s (but `int?`s aren't `int`s without guarding against nulls). By contrast, if a method takes `Optional` then you have to wrap every `Integer` you have to call that method (with something like `Optional.of(something)`).

The author might be wrong about Swift being an example of Solution 1 (looking at Swift's nullability syntax).

But the point is that nullable types provide a bit more power because they're not just a data-structure, but a language feature. If you look at the source of `Option` in Rust, it's an enum like `Result` or (kinda) anything you could write rather than a language feature. Rust has built-in some things like the `?` "try" operator for special enums like `Option` and `Result` to unwrap them (or error), but it isn't quite the same as the null-guards in Dart/Kotlin and you still need to wrap them for functions like `Some(myVar)` rather than being able to pass `myVar` directly for an `Option` parameter.

Again, they are almost the same, but they do talk about reasons for choosing Solution 2 over Solution 1. In Rust, you pattern-match like `match myVar { Some => x(); None => y() }` which is very functional, but they wanted something that felt like traditional null checks with conditionals. They note that nullable types are basically erased at runtime - an `int?` at runtime is either something like `7` or `null`. At compile time, you've checked that you're never assigning a `null` to an `int`, but the runtime doesn't need to know anything about it because the compiler has checked everything. Rust's enums aren't just a single special case, but something that you could make more complicated. Maybe you want a `SchrodingersResult` which could have `Success`, `Err`, or `Huh`. Ultimately, something like `Option` is an algebraic data type that you can compute off of - ex. pattern-match. The runtime needs to know that it's an `Option` because you can write code for that.

It is almost the same. The question is whether you create a one-off language feature for nullability and get advantages like knowing that any `int` can be assigned to an `int?` without needing to wrap it or whether you decide to create a type that works like any other type in your system like Java's `Optional`. Both are reasonable ways to go, but they have subtle differences and the article outlines a lot of those differences.

Re: Why nullable types?

#43
post #36

Earlier quoted context omitted.

In Rust, you would implement From and From for a custom Error enum defined in your application/library. This will allow you to convert any ErrorA or ErrorB into Error. Then, you could simply return Result from your function, and the conversion would happen for you behind the scenes. Of course, unless you track the original error types, you will lose some information. But it’s a very clean way to handle multiple error…

> This will allow you to convert any ErrorA or ErrorB into Error. I chose my example for cases where I want to keep track of the different error cases. But even if I don't, I still have a _lot_ of overhead for converting them. Unfortunately Rust isn't a language that offers a solution to this problem so far. But there is an open RFC for it: https://github.com/rust-lang/rfcs/issues/294

I see. Yeah, this approach breaks down a bit if the error conversion logic is non-trivial.

Re: Why nullable types?

#44
post #32

Earlier quoted context omitted.

That's an interesting counter point, though another comment in a different post for this same article[1] pointed out that Dart is considering adding pattern matching too. Though I have trouble understanding how a nominal type system affects this? Does dart not have generics? That's all you need to support these patterns? I'm having trouble understanding how the type of type system plays a role here. Also, what's 'imp…

Yes Dart has generics which is how you would implement optional types yourself. The type of type system doesn't play a role here you are right. I was thinking of the really good pattern matching I have experienced usually being present with structural subtyping. Dart is considering adding pattern matching (and real tuples!) and I think they will eventually get there. I just think that would have had to come first to…

You may prefer

    for foo in maybeFoo { ... }
This (AIUI) isn't valid Dart code though, but this would be:

    maybeFoo.forEach((foo) { ... })

Re: Why nullable types?

#45
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…

I agree with all your other points but

> > We can’t perform arithmetic on an Option any more than we could on a List.

> Why not? One sensible definition is (...)

It's not the only sensible definition. It would be equally sensible to implement it as:

    Some(x) + Some(y) => Some(x+y)
    Some(x) + None => Some(x)
    None + Some(y) => Some(y)
    None + None => None

Re: Why nullable types?

#46
post #43

Earlier quoted context omitted.

> This will allow you to convert any ErrorA or ErrorB into Error. I chose my example for cases where I want to keep track of the different error cases. But even if I don't, I still have a _lot_ of overhead for converting them. Unfortunately Rust isn't a language that offers a solution to this problem so far. But there is an open RFC for it: https://github.com/rust-lang/rfcs/issues/294

I see. Yeah, this approach breaks down a bit if the error conversion logic is non-trivial.

Actually, I'm wrong here, it's tagged union types not plain ones. But some commentary in there explains it better than me, so still helpful.

Re: Why nullable types?

#47
post #31

Working with Dart now and it looks like it’s straight from the 90’s in a lot of aspects. It is not s bad as vanilla JS but when given a clean slate to design a new platform so many better choices could have been made...

I use Dart every now and then and for me "straight from the '90s" is a benefit. I learned the language in about a day. IDE works great, no issues with autocomplete whatsoever (which is often an issue in "modern" languages).

Re: Why nullable types?

#48

>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…

> 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.

Option types can be nested, nullable types cannot.

Re: Why nullable types?

#49
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…

Adding an `Option` type to an existing language doesnt really solve many problems unless you can also somehow remove it's existing support for `null. Java added `Optional` and while it makes interacting with newer API's clearer, there is nothing preventing you from passing a null Optional. I think if you are designing a language from scratch, you should avoid null, but nullable types are a good feature for existing l…

Language culture matters. Scala has both `Option` and `null`, but there's a strong culture of "`null` is only for Java interop", so you very rarely see a `null` in the wild from libraries, or wonder whether it'd be valid to pass it in.

Re: Why nullable types?

#50
post #31

Working with Dart now and it looks like it’s straight from the 90’s in a lot of aspects. It is not s bad as vanilla JS but when given a clean slate to design a new platform so many better choices could have been made...

I use Dart every now and then and for me "straight from the '90s" is a benefit. I learned the language in about a day. IDE works great, no issues with autocomplete whatsoever (which is often an issue in "modern" languages).

Most mobile developers come from Kotlin or Swift, that are pretty similar to each other and Kotlin is the official language for Android anyway. I had no trouble doing Kotlin coming from a Swift background, the differences are related to the fact it's a JVM language running on Android but the ideas are largely the same.

It would make bridging for native plug-ins a lot easier as well. I don't know how Google Flutter interfacing Google Android could look so medieval when they're basically the same company. They managed to make Xamarin look great in comparison.

Post reply on HN