Live data from Hacker News

Why nullable types?

medium.com

71–80 of 119 posts

Re: Why nullable types?

#71

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…

In terms of compiler comfort I'd much rather the compiler be able to look at func(3) and deduce that "func accepts an int" rather than "maybe func accepts an int and maybe func accepts an Option"

Re: Why nullable types?

#72

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

> No, this is valid in languages with nullable types:

> String s = null;

Only in languages with default-nullable types, (where the non-nullable form, if it exists at all, would be something like “String s!”); in languages with explicity billable types, the above is not allowed, because you would need to explictly opt-in to nullability:

  String s? = null

Re: Why nullable types?

#73
post #63

This is a very readable writeup. From a distance, Dart seems to focus on usability, while other languages focus more on simplicity (Go) or expressive power (most modern languages). I appreciate the focus on usability. It's not unique to Dart (Python, ...), but many languages that are popular around here tend to favor expressiveness over usability.

> Dart seems to focus on usability, while other languages focus more on simplicity (Go) or expressive power (most modern languages). Author here. I think we try to focus on all three, but the latter are largely constrained by the language as it was designed in Dart 1.0 (which was mostly done by a different set of people than the ones who work on the language now). I do wish Dart was a simpler language and worry a lot…

You don't necessarily have to take away features to reduce cognitive load. You can actually reduce it by adding features in some cases.

For example, I believe that adding Sum Types would actually simplify most class-based languages, because it would mean that you can use a straightforward tool with a 1:1 mapping from real-world concept to language concept for representing "or" (a very fundamentally logical construct!). As-is you have to use an awkward inheritance pattern with classes. Or use a union and keep track of the tag manually. There's an extra feature, but the usages of the feature become straightforward. It's the same principle as writing longer but more straightforward code rather than a gnarly one-liner.

Re: Why nullable types?

#74
Back when I was really into FP, but didn't use functional languages, I decided that the humble list was the answer to all my problems. Operations over lists behave the same regardless of their length, and a 0 element list is not a special case. Say you want to send mail to someone's mailing addresses:

    addresses = user.addresses()
    for address in addresses {
        send_mail(address)
    }
If they have no addresses, the program doesn't blow up. If they have one address, they get mail!

Of course, it's possible that having two addresses is just as annoying as having 0 addresses, in which case lists don't help you. Someone will add a second address, and then you won't know where to walk to to go see them.

I'll also point out that it's the same number of lines of code as just handling null:

    address = user.address()
    if address != null {
        send_mail(address)
    }
So it's kind of a wash, and I haven't really thought about it since.

Re: Why nullable types?

#75

I sometimes wonder if the problem is that we don't have enough nulls. null is typically used as a flag value, but the meaning can be ambiguous: maybe it's the absence of a value, maybe an error occured, etc. Sometimes it has more than one meaning for the same type. Maybe types should be allowed to declare multiple nulls (effectively like an Enum in java) for different flag values. Operations on the different nulls wo…

Completely reasonable request, easy to implement along the lines of:

    public class Name {
        private Name(String name, int flag){...}
    
        public static Name asMissing(){new Name(null, -1);}
        public static Name asNotApplicable(){new Name(null, -2);}    
        public static Name asNotAvailableYet(){new Name(null, -3);}        
        public static Name asForbidden(){new Name(null, -4);}        
        public static Name create(String name){new Name(name, 0)}
        
        public boolean isMissing(){flag==-1}
        public boolean isNotApplicable(){flag==-2}
        public boolean isNotAvailableYet(){flag==-3}
        public boolean isForbidden(){flag==-4}
        public String get() {if (flag!=0) throw new Exception(flag) else name}
    }

Re: Why nullable types?

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

By compose I quite literally mean the compose function.

    const add3 = val => val + 3;
    const multiplyBy10 = val => val * 10;
    const subtract5 = val => val - 5;

    const doABunchOfMath = compose(add3, subtract5, multiplyBy10);

    const ninetyEight = doABunchOfMath(10);

    const optionallyNinetyEight = Some(10).map(doABunchOfMath)
That Dart already provides these extensions feels like they are providing an optional type but through a more complicated mechanism than a simple class

Nowhere in any of the functions I wrote above do I as a user have to worry about handling the case where no number exists, that's handled by the option type and signified by the type (The value in the option may or may not exist) and I can write my functions without ever having to worry about handling that case

Re: Why nullable types?

#77

Back when I was really into FP, but didn't use functional languages, I decided that the humble list was the answer to all my problems. Operations over lists behave the same regardless of their length, and a 0 element list is not a special case. Say you want to send mail to someone's mailing addresses: addresses = user.addresses() for address in addresses { send_mail(address) } If they have no addresses, the program d…

In many cases you'd want your program to blow up in some form when trying to send mail to someone without an email address, because that would be better than silently assuming they received a message you never ended up even trying to send.

Re: Why nullable types?

#78

Back when I was really into FP, but didn't use functional languages, I decided that the humble list was the answer to all my problems. Operations over lists behave the same regardless of their length, and a 0 element list is not a special case. Say you want to send mail to someone's mailing addresses: addresses = user.addresses() for address in addresses { send_mail(address) } If they have no addresses, the program d…

While this is true, this kind of flexibility makes the other layers harder.

On the database side, if you use a relational store, it forces you to normal form 5 which few people are used to.

On the front end, allowing everywhere an arbitrary number elements instead of mandatory one, means you need custom widgets everywhere. You need a way of marking the default one. Validation also gets exponentially more complicated.

On the UX side, people are simply not used to this level of flexibility. It will get labeled as impenetrable.

As much as I like the idea, and believe it is elegant, most probably YAGNI.

Re: Why nullable types?

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

You missed out the most interesting one, which is 'reduce':

    extension NullableIteratorExtensions on Iterator {     
      T? reduce(T? Function(T,T) f, T? x0)
         => this.moveNext()
            ? (this.reduce(f, (x0 == null || this.current == null) ? null : f(x0,current)))
            : x0;
    }
Not sure if this is the best notation but then I've never written Dart before.

Of course this is all a bit easier to read if we use some syntax specially built for Monads such as Haskell's do syntax:

    reduce f (head:tail) x0 = do { x 
which has the advantage that it works for all Monads.

Re: Why nullable types?

#80

Earlier quoted context omitted.

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

> I'm not sure what you mean by "compose". The simplest illustration is the ability to have multiple levels of semantically meaningful optionality: Option > is a meaningful type, and None, Some(None), and Some(Some(1)) are all meaningfully-distinct values. int? doesn't compose to int?? and has no good way to differentiate what Option > represents as None and Some(None).

Ironically the main advantage of Monads is that Option> has a natural transformation to Option.
Post reply on HN