Live data from Hacker News

Null References: The Billion Dollar Mistake

infoq.com

91–100 of 158 posts

Re: Null References: The Billion Dollar Mistake

#91

Null references are not a mistake, they make perfect sense. Letting nullable types be dereferenced directly is the mistake. Null references are at the core of a great number of sensible datastructures, and they're a natural fit for conventional computers.

There are two separate concepts here that often gets conflated.

There's null reference in a sense of a special pointer value (usually all bits set to 0) that means "this doesn't point to anything". That's a useful low-level tool that allows for compact representation of many important data structure.

And then there's null reference in a sense of type systems. To be more specific, "null reference" here is really a shortening of "every reference in the type system is implicitly nullable". And that is the billion dollar mistake.

An explicitly nullable reference type that requires explicit check on dereference, or option types, that use null pointers under the hood, are obviously not the problem.

Re: Null References: The Billion Dollar Mistake

#92

Earlier quoted context omitted.

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…

Sure it's up to the language design, but in practice a `None` gets a similar treatment as an empty collection, usually effectively short-circuiting remaining calculations. As the parent poster pointed out, this might either be the behavior you want, or actually mask the error, depending on the situation. By this logic, optionals aren't better than null refs, just different. The same argumentation holds for exceptions…

In practice, usually any operation on optionals with such short-circuiting behavior must be explicit. For example, for member access, instead of foo.bar, you get something like foo?.bar - and that ? right there tells you all you need to know.

Same thing with exceptions/error types. With exceptions, propagation is implicit, but with error types, you usually have to use some explicit proceed-or-propagate operator.

Re: Null References: The Billion Dollar Mistake

#93
post #91

Null references are not a mistake, they make perfect sense. Letting nullable types be dereferenced directly is the mistake. Null references are at the core of a great number of sensible datastructures, and they're a natural fit for conventional computers.

There are two separate concepts here that often gets conflated. There's null reference in a sense of a special pointer value (usually all bits set to 0) that means "this doesn't point to anything". That's a useful low-level tool that allows for compact representation of many important data structure. And then there's null reference in a sense of type systems. To be more specific, "null reference" here is really a sho…

Just consider all pointers null until proven otherwise, shouldn't be that hard to do something like this in static analysis. Even if a reference is non-null, you still have to wonder if it's valid.

Re: Null References: The Billion Dollar Mistake

#94

Earlier quoted context omitted.

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

The problem GP was raising is on the other half of Optional: when you do finally need an int. Say, you want to do arr[*increment(maybeInt)] //error: can't dereference Optional Now, if you as a programmer don't think increment(maybeInt) can actually return None in your particular case, you will probably do the minimal work to convince the compiler to let it go, say matchOptional( increment(maybeInt), someInt => {retur…

This is a corner case, though, and one that is itself a code smell (i.e. in well-written code, it should be very rare). Having implicit null references, and implicit null checks on dereference, optimized for rare a corner case to the detriment of safety in typical code patterns, is a bad thing.

And it definitely is a significant source of errors in managed memory languages, from my experience in C# and Python. It can also be pretty tricky to track down, when the code producing the null happens to run long before the code dereferencing it.

Re: Null References: The Billion Dollar Mistake

#95

Earlier quoted context omitted.

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

The problem GP was raising is on the other half of Optional: when you do finally need an int. Say, you want to do arr[*increment(maybeInt)] //error: can't dereference Optional Now, if you as a programmer don't think increment(maybeInt) can actually return None in your particular case, you will probably do the minimal work to convince the compiler to let it go, say matchOptional( increment(maybeInt), someInt => {retur…

If it really can't ever be null, then it should just be an int, not an Optional. The entire reason that it is an Optional is that it CAN be null.

In this hypothetical language, not initializing an int is a compiler error, assigning null to an int is a compiler error, etc. If it's an int it literally cannot be null.

What ends up happening in practice is that the null is handled close to where it's created, and the rest of the code passes around an int you know isn't null, because people don't feel like passing around an Optional and being forced to check it everywhere.

Sure, you can intentionally write code that does the wrong thing in any language, but the "return 0;" would be a very obvious error in even cursory code review.

Re: Null References: The Billion Dollar Mistake

#96
post #78
post #34

Earlier quoted context omitted.

Imho, Rust is an awkward language because it positions itself as a systems language but it makes low-level stuff more difficult (there's even a book teaching how to implement doubly linked lists in Rust [1]), hence prone to mistakes. At the same time, people are using Rust to build non-systems programs, where other languages would be more appropriate (e.g. those with garbage collectors). I don't think it is a good id…

Rust is a force for good but I think Andrei Alexandrescu was right when he said Rust feels like it "skipped leg day" (in the sense that it has its party piece and not much else) - from the perspective of the arch metaprogrammer himself at least. Rust is obviously good for safety but for everything else (to me at least) it seems unidiomatic and ugly, admittedlty I've never really sunk my teeth into it (I've read a fai…

>> unidiomatic and ugly

I am not sure I would take anyone seriously who thinks this is a valid point to make about a programming language.

Re: Null References: The Billion Dollar Mistake

#97
post #91

Null references are not a mistake, they make perfect sense. Letting nullable types be dereferenced directly is the mistake. Null references are at the core of a great number of sensible datastructures, and they're a natural fit for conventional computers.

There are two separate concepts here that often gets conflated. There's null reference in a sense of a special pointer value (usually all bits set to 0) that means "this doesn't point to anything". That's a useful low-level tool that allows for compact representation of many important data structure. And then there's null reference in a sense of type systems. To be more specific, "null reference" here is really a sho…

> "null reference" here is really a shortening of "every reference in the type system is implicitly nullable"

I don't think this is quite accurate, there are definitely cases where non-null pointers are required (e.g. dereferencing). It's more correct to say that the type system does not explicitly indicate whether a pointer might be null or not.

Re: Null References: The Billion Dollar Mistake

#98

Earlier quoted context omitted.

Good list. I've found the consequences of a nil type are less severe in dynamic languages, where all variables have the Any type, since nil is just one of the options one needs to account for. Static languages where everything is nullable are reneging on the promise; you say something is a String but that just means Option , and it saps a lot of the reasoning power which static typing should give.

`let s:String` is not the same as `let s:String?` in Swift, at least. (Nor in TypeScript)

Right, that's why Swift is in the lists above. TypeScript would've been a good addition, I just didn't think of it.

Re: Null References: The Billion Dollar Mistake

#99
post #90

Out of all possible gotchas in programming languages I still find null pointers the easiest one to discover and fix. You directly see when and where it happens, and the fix is usally straightforward. Compared to that invalid pointers (stale references) are a lot more painful, since programs might continue to work for a while. Managed languages do at least prevent those. Multithreading issues are imho the biggest pain…

You directly see where the null dereference happens. But that's not necessarily where the problem actually is, because a null pointer can flow through a lot of code before it actually gets dereferenced. So "program continues to work for a while" is also a thing with them. In a language like C, a null pointer can also become an invalid non-null pointer pretty easy with pointer arithmetics.

Easy, just add "if (thing == null) return;" to the top of the function that crapped out on a null reference and close the ticket! /s

Re: Null References: The Billion Dollar Mistake

#100
post #73

Earlier quoted context omitted.

The reason they come up again and again is that it's hard to design an imperative language without them (try, assuming you want to provide generic user-defined data structures that allow for cycles). As a result, calling them a "mistake" is reasonably dishonest, as it implies there was an obvious, better alternative.

Can you give some more details on what the design problem is here? It seems to me that nullable references are isomorphic to having an option type with non-nullable references, but prevent accidental unchecked dereference. What are some of the difficulties that you'd expect to come up if you took an imperative language with nullable references and replaced them with options of non-nullable references?

I don't consider 'option' types to have interesting semantic differences with nullable types. YMMV.

But beyond that, the absence of nullable references (really, a valid default value for every type) is a problem for record/object/struct initialisation - you either have to provide all values at allocation time, or attempt to statically check that the object is fully initialised before any use - Java has rules to that effect for 'final' fields, and they are both broken and annoying (less broken rules would likely just be more annoying).

Post reply on HN