Live data from Hacker News

Null References: The Billion Dollar Mistake

infoq.com

21–30 of 158 posts

Re: Null References: The Billion Dollar Mistake

#21
post #3

This comes up again and again in one form or the other, yet new languages still seem to be making the same mistake. Of all languages I've touched, Rust seems to be the only one that mostly circumvents this problem. Are there other good examples?

> Rust seems to be the only one that mostly circumvents this problem. Are there other good examples?

Rust is not the first one to have an Option type; it's a common feature of functional languages because they have ADTs ( https://en.wikipedia.org/wiki/Algebraic_data_type )

Re: Null References: The Billion Dollar Mistake

#22

This old chestnut again. There is an inherent problem in designing processes and writing code to capture them: The notion of not-a-value. There are great many ways to solve them. The most common ones are 'null' and 'Optional[T]'. Neither just makes the problem magically go away. If a process is designed (or a programmer writes it) thinking that 'ah, well, here, not-a-value cannot happen', but it can, then.. you have…

The goal of `Optional[T]` is not to "make the problem magically go away", in fact that is almost the opposite of the goal.

Optional[T] exists to make it very obvious when a value is nullable. Having non-nullable types as default, with Optional[T], allows a developer to model a system more accurately. This is helpful both to the compiler as well as anyone else who reads/maintains that code.

> Imagine, for example, in an Optional based language, that you just map the optional to a lambda to execute on the optional, and the behaviour of the optional is to then simply silently do nothing if it's optional.none. That'd be a much harder to find bug than a nullpointer error. (errors with stack traces pointing at the problem are obviously vastly superior to mysterious do-nothing behaviour with no logs or traces of any sort!).

This is just one of the things a developer could decide to do when faced with an optional which is none. It is up the language design to make it easy to express this behavior (or any other behavior they might choose) without hiding it.

Re: Null References: The Billion Dollar Mistake

#23
post #9
post #3

This comes up again and again in one form or the other, yet new languages still seem to be making the same mistake. Of all languages I've touched, Rust seems to be the only one that mostly circumvents this problem. Are there other good examples?

I assume two reasons, efficiency and because an efficient implementation of mutable state would have the same problem. Right now, a single sentinel value makes a pointer null or not null (0x0 is null, everything else is not null). This is exactly how you'd implement a stricter type, like "Maybe". Encoded as a 64-bit integer, "Nothing" would be represented as 0x00000000 and "Just foo" would be represented as 0xfoo. No…

That's not the same thing as a null pointer because Nothing isn't allowed in place of e.g. integers, strings, etc. like in Java. What you're doing is defining a non-total function. Haskell, per default, doesn't perform exhaustivity checks when pattern matching, but you can enable that via a compiler flag - then it won't let you compile your example. Ocaml, for example, does that by default.

Re: Null References: The Billion Dollar Mistake

#24

This old chestnut again. There is an inherent problem in designing processes and writing code to capture them: The notion of not-a-value. There are great many ways to solve them. The most common ones are 'null' and 'Optional[T]'. Neither just makes the problem magically go away. If a process is designed (or a programmer writes it) thinking that 'ah, well, here, not-a-value cannot happen', but it can, then.. you have…

> There are great many ways to solve them. The most common ones are 'null' and 'Optional[T]'. Neither just makes the problem magically go away. If a process is designed (or a programmer writes it) thinking that 'ah, well, here, not-a-value cannot happen', but it can, then.. you have a bug.

> Some language features might make it possible to help reduce how often it occurs, but eliminate it? I don't think so.

On the contrary, you can 100% eliminate it by forcing null handling at compile time with your `Optional` type. Haskell and some other strongly-typed languages do this (but they call it Maybe).

The way to do this in a C-syntax-ish language would look something like this:

    Optional increment(Optional i) {
        // return i + 1; would throw an error at compile time,
        // because Optional doesn't implement the + operator

        // i.applyToValue would throw an error at compile time
        // if you didn't handle both possible cases
        return i.applyToValue(
            ifNull: (void) => { return new Optional(null); },
            ifValue: (int i) => { return i + 1; }
        );
    }
This is syntactically a bit heavy, partly because I was a bit more verbose than a real implementation would need to be, for clarity, and partly because C-style syntax doesn't do this well. Languages that support this generally have some syntactic sugar to make it a bit more terse.

I've argued before on HN that the benefits of strong static typing are overstated, but this is a case where strong static types really do completely eliminate an entire category of errors. Given how common these errors are, not using stronger types in this situation for popular languages has absolutely been a billion dollar mistake.

Re: Null References: The Billion Dollar Mistake

#25

Earlier quoted context omitted.

in languages like c, rust or go, where you can put arbitrary data on the stack, it seems to me as if such issues are less common because you dont have to worry about initializing pointers and allocating memory unless you actually want to put something on the heap. Thus if you make everything a reference in your language its no wonder you run into issues like null-pointers more often

With stack allocation you then encounter problems with object lifetime. Rust solves this problem by binding references to scope, and Go solves this by invisibility changing an allocation to the heap (and uses ref-counting? I think?). I wish C had a feature that would let you allocate something on the stack and then return to the parent stack frame without popping the stack-pointer - that would be handy for self-conta…

Plus also doesn’t the stack need to be small to fit into the CPU cache?

Re: Null References: The Billion Dollar Mistake

#26
post #8
post #3

This comes up again and again in one form or the other, yet new languages still seem to be making the same mistake. Of all languages I've touched, Rust seems to be the only one that mostly circumvents this problem. Are there other good examples?

Haskell, notoriously. I believe it pioneered the ergonomics of the alternatives used elsewhere.

AFAIK Standard ML predates Haskell and it has an option type.

Re: Null References: The Billion Dollar Mistake

#28
post #8

Earlier quoted context omitted.

Haskell, notoriously. I believe it pioneered the ergonomics of the alternatives used elsewhere.

AFAIK Standard ML predates Haskell and it has an option type.

ML is even older than SML and has algebraic data types.

Re: Null References: The Billion Dollar Mistake

#29

This old chestnut again. There is an inherent problem in designing processes and writing code to capture them: The notion of not-a-value. There are great many ways to solve them. The most common ones are 'null' and 'Optional[T]'. Neither just makes the problem magically go away. If a process is designed (or a programmer writes it) thinking that 'ah, well, here, not-a-value cannot happen', but it can, then.. you have…

The goal of `Optional[T]` is not to "make the problem magically go away", in fact that is almost the opposite of the goal. Optional[T] exists to make it very obvious when a value is nullable. Having non-nullable types as default, with Optional[T], allows a developer to model a system more accurately. This is helpful both to the compiler as well as anyone else who reads/maintains that code. > Imagine, for example, in…

Not contradicting, just that there a slight benefit in reifying an issue as it opens for notation and operators to simplify it. Maybe monad or option chaining are more than making the thing obvious, it make them half disappear.

Re: Null References: The Billion Dollar Mistake

#30
post #3

This comes up again and again in one form or the other, yet new languages still seem to be making the same mistake. Of all languages I've touched, Rust seems to be the only one that mostly circumvents this problem. Are there other good examples?

> Rust seems to be the only one that mostly circumvents this problem. Are there other good examples?

Swift, Kotlin, and of course older languages of a functional bend like MLs, Haskell, Idris, Scala, …

Some are also attempting to move away from nullable references (e.g. C#), though that is obviously a difficult task to perform without extremely severe disruptions.

Post reply on HN