How many problems are actually caused by null (in particular, how many billions of dollars?) While pointers which point into the wrong place for various reasons (off end of array, previously freed memory) cause horrible issues to this day, I can't personally remember ever having a serious issue with a null pointer (they tend to crash quickly and loudly, because in all modern OSes dereferencing NULL segfaults)
I don't know about it in terms of money loss, but generally having missed checks caught at compile time rather than having the program crash is a good thing.
Why Maybe Is Better Than Null
11–20 of 133 posts
Re: Why Maybe Is Better Than Null
#12In doing so, Java makes it just that much easier to create bottom values when they are not desired (e.g., dereferencing a null pointer).
Re: Why Maybe Is Better Than Null
#13 case a of
Nothing -> Nothing
Just a -> case b of
Nothing -> Nothing
Just b -> a + b
This is quite a bit of boilerplate hiding the expression that actually matters--a + b! Moreover, whenever you have code that creeps steadily to the right, it means you either messed up or missed an abstraction.It turns out that this pattern--do a computation if all the values are present, but return Nothing if any of them are Nothing--happens very often. Happily, we can get some nice syntax for Maybe computations like this using do-notation in Haskell or for-comprehensions in Scala:
do a
This is much better! It makes even more sense for more complicated expressions, especially when later results depend on values of earlier ones. However, for a simple example like a + b, it's still quite a bit of boiler plate; we can certainly do better! Here are two alternatives using functions from the Control.Applicative module: (+) a b
liftA2 (+) a b
The important idea here is that both versions somehow "lift" the (+) function to work over Maybe values. This just means they create a new function with checks for Maybe built in. This is great because it saves all the boilerplate above and nicely abstracts away most of the null checks while preserving safety. But the syntax is still a bit awkward. Happily, if you don't mind using a preprocessor[1], you can get some very nice syntax called "idiom brackets": (| a + b |)
[1]: https://personal.cis.strath.ac.uk/conor.mcbride/pub/she/The computation inside the (| and |) is lifted over Maybe, just like the two previous examples. I think this is the clearest option here: it has the least syntactic overhead, and the base expression--a + b--is very easy to read. They also have the advantage of nesting, so you can express a + b + c, where you want a null check for all three variables, as:
(|(|a + b|) + c|)
This isn't perfect, but I think it's still very easy to follow. It might be better if the (| and |) were a single character, something like this: ⦇⦇a + b⦈ + c⦈
However, some people really don't like Unicode symbols in their code :(. Happily, you can have the source look like (|foo|) and have Emacs replace it with ⦇foo⦈ without actually changing the code. It's basically Unicode syntax highlighting. I think this leads to the most readable code so far.So my main point is that you can abstract out the common case where you check for Nothing and make the whole expression Nothing if any sub-expression is. This saves quite a bit of typing and much more importantly makes the resulting code far easier to read.
Another really cool part is that all these syntax forms and functions are not specific to Maybe--they actually work for a whole bunch of different types. So you would not be bloating your language by including special features just for safely checking nulls; these features are much more general.
Re: Why Maybe Is Better Than Null
#14How many problems are actually caused by null (in particular, how many billions of dollars?) While pointers which point into the wrong place for various reasons (off end of array, previously freed memory) cause horrible issues to this day, I can't personally remember ever having a serious issue with a null pointer (they tend to crash quickly and loudly, because in all modern OSes dereferencing NULL segfaults)
if (argumentX == null)
return null;
at the top of function signatures. It was just defensive programming. Maybe argumentX couldn't be null, but it would take time to figure that out (sometimes I did that, though). More code means harder to read and maintain, thus costing dollars.This would also be contagious: If a piece of code checks if X is null, you'll assume that X can be null, whether or not that's true.
I'd certainly prefer to be able to reason about the code with the safe assumption that certain things cannot be null.
Re: Why Maybe Is Better Than Null
#15This article makes it seem like you'd have to explicitly check whether a Maybe value is Nothing when you use it. This is certainly safe , but it's also very awkward; as a contrived example, adding two numbers would look like this: case a of Nothing -> Nothing Just a -> case b of Nothing -> Nothing Just b -> a + b This is quite a bit of boilerplate hiding the expression that actually matters--a + b! Moreover, whenever…
(fromMaybe 0 a) + (fromMaybe 0 b)
This will always produce a number and it's pretty clear why you'd get the one you'd get.Re: Why Maybe Is Better Than Null
#16That is, if you are going to use Maybe, you either want to do so from the beginning, or you want a good layer of abstraction between where the value is optional and where it is not. Moving something from guaranteed to optional is a bit more combersome with Maybe.
Also, I have gotten really used to "truthy" values.
Re: Why Maybe Is Better Than Null
#17How many problems are actually caused by null (in particular, how many billions of dollars?) While pointers which point into the wrong place for various reasons (off end of array, previously freed memory) cause horrible issues to this day, I can't personally remember ever having a serious issue with a null pointer (they tend to crash quickly and loudly, because in all modern OSes dereferencing NULL segfaults)
I've worked with a code base in C++ where the code base would accumulate significant amounts of if (argumentX == null) return null; at the top of function signatures. It was just defensive programming. Maybe argumentX couldn't be null, but it would take time to figure that out (sometimes I did that, though). More code means harder to read and maintain, thus costing dollars. This would also be contagious: If a piece o…
Re: Why Maybe Is Better Than Null
#18This article makes it seem like you'd have to explicitly check whether a Maybe value is Nothing when you use it. This is certainly safe , but it's also very awkward; as a contrived example, adding two numbers would look like this: case a of Nothing -> Nothing Just a -> case b of Nothing -> Nothing Just b -> a + b This is quite a bit of boilerplate hiding the expression that actually matters--a + b! Moreover, whenever…
instance Num a => Num (Maybe a) where
(+) = liftM2 (+)
(-) = liftM2 (-)
(*) = liftM2 (*)
abs = liftM abs
signum = liftM signum
negate = liftM negate
fromInteger = Just . fromInteger
> Just 4 + 2 * Just 6
Just 16
> Nothing * 42
Nothing
Notice how the fromInteger method allows you to freely mix Maybe and non-Maybe numbers.Re: Why Maybe Is Better Than Null
#19How many problems are actually caused by null (in particular, how many billions of dollars?) While pointers which point into the wrong place for various reasons (off end of array, previously freed memory) cause horrible issues to this day, I can't personally remember ever having a serious issue with a null pointer (they tend to crash quickly and loudly, because in all modern OSes dereferencing NULL segfaults)
Re: Why Maybe Is Better Than Null
#20This article makes it seem like you'd have to explicitly check whether a Maybe value is Nothing when you use it. This is certainly safe , but it's also very awkward; as a contrived example, adding two numbers would look like this: case a of Nothing -> Nothing Just a -> case b of Nothing -> Nothing Just b -> a + b This is quite a bit of boilerplate hiding the expression that actually matters--a + b! Moreover, whenever…
You can also make Maybe an instance of various typeclasses for even nicer syntax: instance Num a => Num (Maybe a) where (+) = liftM2 (+) (-) = liftM2 (-) (*) = liftM2 (*) abs = liftM abs signum = liftM signum negate = liftM negate fromInteger = Just . fromInteger > Just 4 + 2 * Just 6 Just 16 > Nothing * 42 Nothing Notice how the fromInteger method allows you to freely mix Maybe and non-Maybe numbers.