I think I prefer the Option method, used in Rust. I think mainly because Option makes it more obvious, and adds more friction for using nullable types, whereas adding it into the type system makes...
I think I prefer the Option method, used in Rust. I think mainly because Option makes it more obvious, and adds more friction for using nullable types, whereas adding it into the type system makes it too easy. It probably isn't quite as bad as in languages where everything is nullable, but I think the friction of Option is actually a pro, not a con, as it makes it very explicit that you're dealing with an nullable value.
Well, maybe, but it’s hard to add much verbosity when people aren’t used to it. At least nullable types aren’t the default anymore in Dart, and it seems it took quite a lot of work to get there....
Well, maybe, but it’s hard to add much verbosity when people aren’t used to it. At least nullable types aren’t the default anymore in Dart, and it seems it took quite a lot of work to get there.
Dart was originally designed to be familiar to Java and JavaScript programmers. Rust is more of a fresh start in comparison. You’re expected to have to work a bit to learn it.
Most of the discussion surrounding this article has focused on the wrong things. The only difference between nullable and optional/maybe types is this: data Maybe a = Just a | Nothing data Maybe...
Most of the discussion surrounding this article has focused on the wrong things. The only difference between nullable and optional/maybe types is this:
In other words, maybe types let you distinguish between just Nothing and Nothing, where nullable types do not. Aside from that, you can use identical syntax and provide most of the same stdlib affordances. It's purely a semantic distinction.
The article does explain that. But there is a second difference, which is that a non-null type T is a subtype of the nullable type T?. This isn’t true of T and Maybe<T>. Furthermore, in Dart a...
The article does explain that. But there is a second difference, which is that a non-null type T is a subtype of the nullable type T?. This isn’t true of T and Maybe<T>. Furthermore, in Dart a List<T> is a subtype of List<T?>.
Right; I was referring to the subsequent discussion which seems to have missed the meat of the article. This is true, but not particularly interesting. It's easy to have an implicit conversion...
The article does explain that
Right; I was referring to the subsequent discussion which seems to have missed the meat of the article.
non-null type T is a subtype of the nullable type T?. This isn’t true of T and Maybe<T>. Furthermore, in Dart a List<T> is a subtype of List<T?>
This is true, but not particularly interesting. It's easy to have an implicit conversion from x to Maybe x which papers over the difference, or at least shorthand syntax. Ditto for y.map(\i -> Just i).
Mapping each element creates a new list. In functional languages this won’t matter other than for performance. In imperative languages it does, because you can modify the list. (Plus we do care...
Mapping each element creates a new list. In functional languages this won’t matter other than for performance. In imperative languages it does, because you can modify the list. (Plus we do care about performance when the list is large or the conversion is done a lot.)
In a language that allows mutation, the original list and the copy returned by the map() call should not be the same, because you don't want a mutation to the original list to change the copy, or...
In a language that allows mutation, the original list and the copy returned by the map() call should not be the same, because you don't want a mutation to the original list to change the copy, or vice-versa. If the compiler can prove that that it doesn't matter then it could still be done, but it doesn't seem like a trivial optimization?
I think I prefer the
Option
method, used in Rust. I think mainly because Option makes it more obvious, and adds more friction for using nullable types, whereas adding it into the type system makes it too easy. It probably isn't quite as bad as in languages where everything is nullable, but I think the friction of Option is actually a pro, not a con, as it makes it very explicit that you're dealing with an nullable value.Well, maybe, but it’s hard to add much verbosity when people aren’t used to it. At least nullable types aren’t the default anymore in Dart, and it seems it took quite a lot of work to get there.
Dart was originally designed to be familiar to Java and JavaScript programmers. Rust is more of a fresh start in comparison. You’re expected to have to work a bit to learn it.
For everyone who posts that "billion dollar mistake" quote...:
Most of the discussion surrounding this article has focused on the wrong things. The only difference between nullable and optional/maybe types is this:
Whereas:
In other words, maybe types let you distinguish between
just Nothing
andNothing
, where nullable types do not. Aside from that, you can use identical syntax and provide most of the same stdlib affordances. It's purely a semantic distinction.The article does explain that. But there is a second difference, which is that a non-null type T is a subtype of the nullable type T?. This isn’t true of T and Maybe<T>. Furthermore, in Dart a List<T> is a subtype of List<T?>.
Right; I was referring to the subsequent discussion which seems to have missed the meat of the article.
This is true, but not particularly interesting. It's easy to have an implicit conversion from
x
toMaybe x
which papers over the difference, or at least shorthand syntax. Ditto fory.map(\i -> Just i)
.Mapping each element creates a new list. In functional languages this won’t matter other than for performance. In imperative languages it does, because you can modify the list. (Plus we do care about performance when the list is large or the conversion is done a lot.)
Assuming that T is a boxed type, none will be indicated by a null box; so it's a trivial optimization to elide the conversion entirely.
In a language that allows mutation, the original list and the copy returned by the map() call should not be the same, because you don't want a mutation to the original list to change the copy, or vice-versa. If the compiler can prove that that it doesn't matter then it could still be done, but it doesn't seem like a trivial optimization?