4 ms·
There's a difference between crashing and returning null. If head returned null on an empty list, that null could be passed around to different places in the pr
by wtetzner 12y ago
There's a difference between crashing and returning null. If head returned null on an empty list, that null could be passed around to different places in the program before it crashed from a null pointer exception.
There can be unexpected crashes in Haskell, but not because of null.
- sparkie 12y agoIt's not equivalent to null, but analagous to it. With lazy evaluation, I can pass also around the expression `head []` to different places, and it won't complain until I attempt to evaluate it - much like a language with null won't complain until you try to dereference it. Sure there's a difference though - you can see immediately where the problem is with Haskell's error, but it's more difficult to trace why a value might be null in imperative code (Which I think has more to do with mutability than the presence of null). I was also highlighting that the tryhaskell REPL actually behaves like null, because it doesn't terminate immediately as you would expect. Just yesterday I was discussing this topic with the author of the Mars language, because his record implementation is equivalent to Haskell's and is flawed in the same way (sum types + records leading to what is effectively the equivalent of `null`) [https://news.ycombinator.com/item?id=8005116 https://news.ycombinator.com/item?id=8005116]. Given a new language like Mars, he could provide a fix, but we have too much baggage to break Haskell's implementation.
- wtetzner 12y ago> With lazy evaluation, I can pass also around the expression `head []` to different places, and it won't complain until I attempt to evaluate it - much like a language with null won't complain until you try to dereference it. It won't complain until you try to evaluate it temporally, but the stack trace will point to the call to head.
- rtfeldman 12y agoYeah. A major reason null is called the "billion dollar mistake" is that once you finally do get a NullPointerException (or the like), it can take a huge amount of time to track down where the null value originated. If you take the head of an empty list in Haskell, you get an exception right away. Not a poisoning of the well, like you do in so many other languages. That's absolutely a benefit of Haskell worth touting.
- T-hawk 12y agoThat's still the same problem, isn't it? You still have to track down where the empty list originated, just as the null value in C. I'm not a Haskeller, but do the language and tools make that easier than in other ecosystems?
- deleted 12y ago[deleted]
- freyrs3 12y agoThe difference is the program halts immediately at the place in the program where the semantics break down. Unlike in C where you can program with nulls and pass them around, potentially smearing the problem around the entire program.
- sparkie 12y agoWhat makes it easier is immutability - if given an empty list, the only place that could've made this list empty is the place it was constructed - because there's no way some other function can come and delete items from it. A function which "removes" items from a list doesn't actually do such thing - it creates a brand new one and adds all the same elements except the items you requested being removed. In this way, there's only one possible path that the list could've come from - through the pure functions which use it - until head is reached. Given that each function is referentially transparent, applying the same input list to a function in the debugger will always produce the same result, so it's simple to call a function with some sample data in ghci, and the result you get will be the same result you get in the compiled program. Debugging/tracing is perhaps more difficult than with tooling you might already be familiar with - but it's much more rare that you need to even use them, because it's obvious what values a function should return - they don't have any state which could influence otherwise.
- wereHamster 12y agoAnd there is a billion ways how to construct an empty list. You can't just grep for '[]'. It can be hidden inside of a 'catMaybes', 'tail', or any other function which returns a list and makes no guarantees about it's size, of which there are plenty.