Live data from Hacker News

What is wrong with NULL

lucidchart.com

51–60 of 147 posts

Re: What is wrong with NULL

#51
I'm still not entirely convinced that NULL is a problem. But how NULL (and pointer types in general) work in C leads to much, much greater problems.

Though, I think uninitialized variables or memory might be just as bad.

Re: What is wrong with NULL

#52
post #4

For statically typed languages this is definitely an issue, but for dynamic languages less so. In Python, I wouldn't use an optional value, x is None seems to be just fine. I'm still waiting for std::optional for C++.

Assuming x is not a boolean, I think not x would be sufficient in the case of Python.

in Python (even for non-Booleans)

  not x 
is not equivalent to "X is not None", since empty lists, zero, etc., are not truthy in a Boolean context.

Re: What is wrong with NULL

#53
One of the problem's Maybe still has is in the deeper question of "why are you expecting None to be here?". Don't get me wrong, there are valid cases for this, and Maybe is certainly preferable to null across the board, but I think the movement to Maybe in the greater programming space will in many cases practically result in trading one set of explicit errors (crashes) for (a more subtle?) set of errors (behavioral). In particular, this style of programming will become frequent (from Swift documentation):

   if let roomCount = john.residence?.numberOfRooms {
      println("John's residence has \(roomCount) room(s).")
   } else {
      println("Unable to retrieve the number of rooms.")
   }
Or from this blog post's own example:

   option.ifPresent(x -> System.out.println(x));
In other words, I think the core problem still hasn't been attacked and we may end up in the same situation we were in with exceptions originally: programmers will just throw up their hands and wrap everything in a Maybe/Optional and/or just maybe-protect until the compiler stops bugging them. At the end of the day, if you ? all your values then you end up with something equivalent to having everything be nullable and correctly null-checking them.

Obj-C had a form of this with nil calling of methods silently doing nothing (so you end up with methods that "conveniently" don't happen, and don't crash! when the receiver is nil). However, despite having lots of legitimate uses (don't bother checking your delegate exists), it can still very silently sneak in to other parts of the code.

Re: What is wrong with NULL

#54
>NULL is a terrible design flaw, one that continues to cause constant, immeasurable pain

Exaggeration much? Certainly not "the worst mistake of computer science". IPv4 is much worse, just for one example. NULL isn't even visible to end-users, many mistakes in CS are quite visible and really impact non-programmers' lives. NULL is just the color of the wallpaper in the engine room.

Re: What is wrong with NULL

#56

We don't need to get rid of null, we need more, type-specific and context-carrying nulls: types need a way to signal various error states via an enumeration of instance constants that carry the error state in a type-compatible manner without some syntactically crappy mechanism like Maybe. class Connection { //Error instances BAD_ADDR("The given address was not correct...") ... } These constants should throw, just lik…

If you have a language with enum types (Haskell, ML, etc., or any of the languages inspired by them like Rust, Scala, etc.), that's straightforward. In e.g. Rust, you'd have

    enum Connection {
        ValidConnection {fd: RawFd, address: SockAddr, ...},
        BadAddr,
        BadPort,
        ...
    }
In fact Rust's representation of the maybe type is just a generic

    enum Option {
        Some(T),
        None,
    }
so all you're doing is getting rid of the two layer Option syntax and making it a single Connection, so you're not writing Option, PossiblyBadAddress, etc. everywhere.

Then all your call sites can do one of two things. Either they can check for specific errors, like

    match conn {
        Connection {fd, address, ..} => write(fd, ...),
        BadAddr => /* handle error */,
        BadPort => /* handle error */,
    }
or you can write a simple function that throws an exception, if you really want an exception-handling style:

    impl Connection {
        fn get_fd(&self) -> RawFd {
            match *self {
                ValidConnection {fd, ..} => fd,
                BadAddr => panic!("The given address was not correct"),
                BadPort => panic!("The given port was not correct"),
            }
        }
    }
and then call conn.get_fd(). For a simple command-line app, panicking and aborting is pretty much what you'd want to do anyway. For a test suite, panics are caught per test case (and you can even test that a function does panic with a given message), so it's very testable.

Re: What is wrong with NULL

#57
post #7
post #3

This mistake is fixed in Haskell.

Rust, too! Edit: Btw, I disagree with how the article categorizes Rust in comparison to Haskell. It shows that Rust has std::ptr::null, but neglects the fact that Haskell has Foreign.Ptr.nullPtr. Either both should be "5 stars" or both should be "4 stars".

Came here to say this. In fact, I think every language that they give 5 stars to has some form of "foreign pointer", "raw pointer", "unsafe pointer" or the like that is nullable, for FFI and other low level tasks.

I think that anything which has no null in normal, idiomatic code, outside of "unsafe", "ffi", or similar subsets, should get 5 stars. The distinction is really about whether you need to worry about any possible value, or any possible reference, being null, which you do in languages like C or Java where all references are nullable.

Giving Java and Rust the same 4 star rating because they both have some form of null and some form of Maybe/Option is a bit misleading. In Rust, Option is what you use in any normal code, and so you don't need to check for Null everywhere. In Java, it's the other way around; nullable references have existed since the beginning and are not segregated in any particular way, while Optional is a recent addition.

Likewise, I think that in Scala and Swift, null is only present for compatibility purposes, and idiomatic code does not use them. I'm not sure about F#. Clojure does use nil idiomatically, and also has '(), which may even count as "multiple NULLs" according to this rubric, though I guess that in Clojure '() is just treated as an empty list, rather than a null value like it is in other Lisps.

Re: What is wrong with NULL

#58

Earlier quoted context omitted.

Assuming x is not a boolean, I think not x would be sufficient in the case of Python.

in Python (even for non-Booleans) not x is not equivalent to "X is not None", since empty lists, zero, etc., are not truthy in a Boolean context.

Ok, yeah, you're right -- I forgot those other cases. Thanks for the clarification.

Re: What is wrong with NULL

#59

NULL is okay as long as you pretend it doesn't exist. I mean, in these languages, uninitialized variables exist at some point (fields start uninitialized in constructor bodies, etc), and that's why there's null, instead of defining them with some garbage value that has undefined behavior. But the right solution for users is to just pretend that it can't exist, and that uninitialized variables have a garbage value. Of…

You can pretend all you want, and sure if you force yourself to always use Option then many problems will go away. It still is a huge hole in your type checking and will still cause mistakes to occur.

It's not a huge hole and not such a big deal. Just don't design APIs to use null. I've done it, and I can tell, you, it works! (But to be fair, I haven't worked on database-backed software in half a decade.) When mistakes do occur they're the trivial kind where you get a stack trace and can work it out.

It's wrong to call null pointers a billion dollar mistake, too -- if we didn't have null (and in the absence of generics that permit Option, as things were long ago), programmers would end up using in-band sentinel values instead. That would be a much worse mistake.

Re: What is wrong with NULL

#60
post #7
post #3

This mistake is fixed in Haskell.

Rust, too! Edit: Btw, I disagree with how the article categorizes Rust in comparison to Haskell. It shows that Rust has std::ptr::null, but neglects the fact that Haskell has Foreign.Ptr.nullPtr. Either both should be "5 stars" or both should be "4 stars".

Author here. I didn't know that about Haskell.

Admittedly, the "rating" is pretty rough, maybe even a bad idea.

I've seen std::ptr::null more than I ever have Foreign.Ptr.nullPtr.

But really, both are usually used for compatibility with external libraries/programs/runtimes, not for idiomatic language programming.

Both great languages in my book :)

Post reply on HN