News for hackers. Stuff that matters.
Re:Null References: The Billion Dollar Mistake by jrockway on Saturday January 11, 2020 @08:49AM (#22019831)
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 object may be stored at the sentinel value, 0x00000000. Exactly the same as what we have now, and provides no assurances that 0xfoo is actually a valid object.

Meanwhile, Haskell which "doesn't have null" crashes for exactly the same reason your non-Haskell program crashes with a null pointer exception:

    f :: Num a => Maybe a -> Maybe a
    f (Just x) = Just (x + 41)
This blows up at runtime when you call f Nothing, because f Nothing is defined as "bottom", which crashes the program when evaluated.

It's exactly the same as langages with null pointers:

    func f(x *int) *int {
        result := *x + 41
        return &result
    }
And the solution is the same, your linter or whatever has to tell you "hey maybe you should implement the Nothing case" or "hey maybe you should check the null pointer".

Where I'm going with this is that you need to develop entirely new datatypes and have an even stricter type system than Haskell. Maybe Rust is doing this, but it's hard. We all know null is a problem, but calling null something else doesn't make the problems go away.

Re:Null References: The Billion Dollar Mistake by anderskaseorg on Saturday January 11, 2020 @09:07AM (#22019912)
> It's exactly the same as langages with null pointers:

Four huge differences:

1. You don’t need to pass around ‘Maybe a’ everywhere. If null isn’t expected as a possible value (which usually it isn’t), you just pass around ‘a’, and when you do use ‘Maybe’ it actually means something.

2. The Haskell compiler can, and does (with -Wall), tell you that your pattern match is non-exhaustive. You don’t need a separate “linter or whatever”. This is possible because the needed information is present in the type system, and doesn’t need to be recovered with a complicated and incomplete static analysis pass.

3. If you do this anyway, the error is thrown at exactly the point where ‘Maybe a’ is pattern-matched, not at some random point several function calls later where your null has already been coerced into an ‘a’.

4. This program is defined to throw an error; it’s not undefined behavior like in C that could result in something weird and unpredictable happening later (or earlier!).

Also, Rust optimizes away the tag bit of ‘Option’ under common circumstances; for example, ‘None: Option<&T>’ (an optional reference to ‘T’) is represented internally as just a null pointer, which is safe because ‘&T’ cannot be null.

Re:Null References: The Billion Dollar Mistake by jrockway on Saturday January 11, 2020 @10:15AM (#22020240)
> You don’t need to pass around ‘Maybe a’ everywhere.

You don't need to pass pointers around everywhere. Languages with null still have value types that cannot be null.

> You don’t need a separate “linter or whatever”.

Optional compiler flags count as "whatever" to me.

> it’s not undefined behavior like in C that could result in something weird and unpredictable happening later (or earlier!)

C++ doesn't define this, but the OS does (and even has help from the CPU).

Anyway, my TL;DR is that it's easy to have a slow program that passes everything by value, or east to have a fast program that uses pointers or references. Removing the special case of null is meaningless, because you can still have a pointer to 0x1 which is just as bad as 0x0, probably. This goes back to my original answer to the question "why don't more languages get rid of null" which was "it's harder than it looks." I think I'm right about that. If it were easy, everyone would be doing it.

Re:Null References: The Billion Dollar Mistake by temac on Saturday January 11, 2020 @05:20PM (#22022766)
> Languages with null still have value types that cannot be null.

Not all languages.

> C++ doesn't define this, but the OS does (and even has help from the CPU).

That's not how it works anymore, because C / C++ front-ends interacting with the optimizers are yielding too "optimized" results. See the classic https://t.co/mGmNEQidBT

Re:Null References: The Billion Dollar Mistake by rowanG077 on Monday January 13, 2020 @07:40PM (#22040535)
Oh boy... `-Wall` is "whatever". Please let me never look at code you have written...
Re:Null References: The Billion Dollar Mistake by dunefox on Saturday January 11, 2020 @09:18AM (#22019970)
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 by tibbe on Saturday January 11, 2020 @09:10AM (#22019928)
This missed the point. The point of not that you can forget to check the null case. The point is that you can express that sometimes there's no null case.
Re:Null References: The Billion Dollar Mistake by jrockway on Saturday January 11, 2020 @10:06AM (#22020196)
The "no null" case in traditional languages is just "int" instead of "*int". All values inside an "int" are valid integers.

Certainly it's problematic to use the same language primitive to mean "a pointer" and "this might be empty", but it's what people use them for in every language that has pointers (that I've used anyway).

Re:Null References: The Billion Dollar Mistake by pornel on Saturday January 11, 2020 @10:19PM (#22024244)
That conflates pass by value/by reference distinction with being optional.

This means you need magic values for "maybe int" with no help from the type system. And you can't express "there's definitely an int at that address".