Live data from Hacker News

What is wrong with NULL

lucidchart.com

71–80 of 147 posts

Re: What is wrong with NULL

#71
post #56

Earlier quoted context omitted.

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

You shouldn't have to specify the error states in each method, this is why what I'm advocating is different than a simple enum: - You don't need to define a constructor to take the error string - You don't need to implement method dispatch (all methods of an error state instance automatically throw, like null does) Enums are close, but not quite right.

Hm, I think what you might want is an enum / sum type, but with the ability to state that a particular variable is statically a particular variant of that enum. So, for instance, I can write fn serve(conn: &Connection::ValidConnection), and it's a type error to pass a generic unchecked Connection to it. Then serve() can go and call other functions that take a ValidConnection without doing any further error handling.

You might, for convenience, have a single method that turns a Connection to a ValidConnection, or else throws, and you can encode your error messages in one place in this method.

I think this proposal permits such a thing, although I haven't read it closely yet: http://smallcultfollowing.com/babysteps/blog/2015/08/20/virt...

Re: What is wrong with NULL

#72
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++.

In dynamically typed languages, there are still problems with flat Null/Nil/None that are addressed by optional values (the biggest comes when you use multiple operations that can return null but the single null value loses the source of the null; using optional values these often are differentiated easily as being either an "outer" null -- e.g., None -- or an "inner" null -- Some(None).) In fact, the example in the…

But as the writer mentions, optionals are a lot like lists with either zero or one elements, so it seems like many of these issues could be dealt with by simply returning a list, which would have zero elements if (in that example) the key was missing, or one element is the key was present. (And that single element would be nil if that was the value for that key.)

Re: What is wrong with NULL

#73
The title originally matched the blog post ("The worst mistake of computer science"), but then it was changed by a moderator.

Maybe it could have been a less drastic change?

"NULL, the worst mistake of computer science"

or

"The worst mistake of computer science: NULL"

Re: What is wrong with NULL

#74
NUL-terminated strings aren't that bad:

* unlike Pascal-style strings, they can be usefully sliced, especially if you can modify them strtok-style.

* unlike (ptr,len) "Modern C buffers"/Rust-style strings, references to them are pointer-sized, and they can be used as a serialization format.

This makes the kind of application that is based on cutting pieces of a string and passing them around a good measure faster, especially compared to say C++'s "atomically reference-counted, re-allocating at the slightest touch" std::string.

This style of programming is not particularly popular nowadays, so buffer-strings are better-fitting. Its main problem is its multitude of edge-cases, which tend to demonstrate C's "every bug is exploitable" problem well.

Re: What is wrong with NULL

#75
post #49
post #3

This mistake is fixed in Haskell.

Not completely. non-nullable by default is nice, ignoring possible nulls is nice, but Haskell's Maybe still suffers from premature generality by conflating all forms of absence. A 'Maybe T' is fundamentally, context-sensitively, not equivalent to any other 'Maybe T' in the same way all 'T's are. This is bad. edit: carsongross beat me to what I'm talking about with a better explanation: https://news.ycombinator.com/it…

Can't you just handle this with something like `Either ErrCode T`?

(And if not, please do explain why!)

Re: What is wrong with NULL

#76
post #10

Uglier than a Windows backslash, odder than ===, more common than PHP, more unfortunate than CORS, more disappointing than Java generics, more inconsistent than XMLHttpRequest, more confusing than a C preprocessor, flakier than MongoDB, and more regrettable than UTF-16, the worst mistake in computer science was introduced in 1965. That could be the greatest intro sentence ever seen on Hacker News.

I also don't think a C preprocessor is at all confusing, it's quite a simple program, both to write and to program. Including less used features such as concatenation or stringification.

Re: What is wrong with NULL

#77

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…

I think Either's handle this really well (and in fact this is more or less how its done with ErrorMonads). You basically return Either Value [Error], which has the benefit of being much more compassable than something that breaks control-flow like try/catch.

For example, if you have something like

    x = emptyStringOnDoesntExist(read(path)) // "" on not exist error BUT NOT permission error
    x = emptyStringOnAnyError(read(path)) // "" on any error
So right now this doesn't seem THAT different than using try/catch to select values depending on the type of error "thrown". But its critical to notice that we are going through normal programming control flow here (we pass in the result value, not some sort of weird function wrapper function that wraps read and inserts a try/catch). This becomes much more apparent how its useful when you have more interesting tasks:

    var filenames = [..,...,..];
    var concated = filenames.reduce(pipe(read, emptyStringOnDoesntExist, concat), "");
So now we've done something really neat: we are concating a bunch of files, and accepting some may not exist, BUT if any of them have a permission error the whole thing will return Either _ [PermissionError]. Now are errors are ACTUALLY composable.

Re: What is wrong with NULL

#78

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

This is a concern, but the advantage to Maybe is it makes this concern very explicit. SML/NJ code will not compile if you don't have a binding to handle the None for an option 'a type. The programmer does of course then have the option of doing

None => raise Error

but practically speaking, when deciding it's time to make your code more robust, it's a lot easier to text search for instances of "None => raise" than to search for the absence of proper handling of the possibility of a null arg or return value.

Re: What is wrong with NULL

#79
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++.

"Python: What You Gain In Prototyping Efficiency And Speed, You Lose In Having To Exhaustively Unit Test Every Line Of Executable Code, Because the Interpreter Cannot Tell You That You Typo'd A Function Name Until It Tries And Fails To Call It At Runtime(TM)" ;)

Re: What is wrong with NULL

#80

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…

> The right language design decision for these languages (managed languages like Java) might have been to make uninitialized references have a garbage value that reliably throws an exception when used (i.e. null) -- you can copy the reference and pass it around, but you can't compare it for equality and any attempt to inspect its value results in an exception.

That's just a different kind of null. You still have the original problem: this thing is declared as a T, but sometimes it's not a T, so you have to inspect how the value is used before you can conclude whether it's a T or not.

The correct solution is to structure the language so access can't occur before initialization. For example, you could place severe constraints on constructors so they must initialize all the fields and do nothing else until that's done. Think initializer lists from C++ (but stricter), or tagged unions from Haskell.

Post reply on HN