Live data from Hacker News

Why Maybe Is Better Than Null

nickknowlson.com

21–30 of 133 posts

Re: Why Maybe Is Better Than Null

#23

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

I'd certainly prefer to be able to reason about the code with the safe assumption that certain things cannot be null.

You can do this, but if you want it to be maintainable, you'll also want to detail in the function comments this technical debt. If you don't, someone else will come along and see your sweet method (looking only at the comments) and use it where the input can be null.

Ex:

  /**
  * This does some stuff.
  * @param entry Does something with this
  * DEBT: Assumes the input entry is not null.
  */
  void doSomething(SomeObject entry) { }

Re: Why Maybe Is Better Than Null

#24

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)

The problem isn't just NULL in C. This post is talking about the entire Null/Nil reference problem across all languages that use a null-type value. This is especially a problem in dynamic languages that sling nils around....like any major modern scripting language. Checking if a value is nil before proceeding is aping what a language like Haskell does when it pattern matches against Maybe (Just a, Nothing) albeit in…

That's the main problem with calling Maybe 'better'. If you don't have static type checking then either you implement it just for Maybe or you end up with the same sorts of problems as you had before.

Making types non-Nullable by default is nice, though. Even in a dynamic language you can have a syntactic distinction to make interfaces more explicit.

Re: Why Maybe Is Better Than Null

#25

Earlier quoted context omitted.

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.

I don't have a whole lot of Haskell experience ... but these "Maybe" unwrapping functions are rare right? Like a null check I'd think that most of the time you make the check when you get the unreliable input or allocation or whatever, and thereafter in the guts of you program you have the certainty that the input has been "checked".

Yes. This is perhaps the most important point in this thread. Monads and idioms are neat, but for Maybe's in most situations they are not really necessary since there is often a single point where you `case` on a Mabye and that's it.

Re: Why Maybe Is Better Than Null

#26
post #13

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

Another way to go would be to use some functions that conceal the mechanics of Maybe. For instance: (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.

I don't agree that it's pretty clear. 0 is a perfectly valid outcome of an addition, and you can't count on being the last calculation in the chain.

Re: Why Maybe Is Better Than Null

#27
post #13

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

Ah yes, wonderfully clear syntax:

    do a 

Re: Why Maybe Is Better Than Null

#28

Earlier quoted context omitted.

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.

I don't have a whole lot of Haskell experience ... but these "Maybe" unwrapping functions are rare right? Like a null check I'd think that most of the time you make the check when you get the unreliable input or allocation or whatever, and thereafter in the guts of you program you have the certainty that the input has been "checked".

Depends on the structure of your program. When the Maybe represents the return value of some function that might fail, like a "null" in another language, you'll probably try to eliminate the Nothing case fairly soon after getting it on, and if you have several to eliminate you might use the monad syntax to avoid repeated checks. (User input will commonly use an Either or Error rather than a Maybe, so that you have some error status for what went wrong, but the same principle applies.)

However, sometimes a Maybe represents an inherently "optional" part of your data model, such as "a Foo may have zero or one Bar". In that case, you'll probably hold onto the Maybe until the point where you'd actually read and use that field.

Re: Why Maybe Is Better Than Null

#29
post #13

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

Ah yes, wonderfully clear syntax: do a

That particular syntax makes much more sense when you have functions that return a Maybe value:

    do a 
I used a deliberately overly simple example so I could go on from do-notation--which many people are already familiar with--to applicatives and idiom brackets.

Besides, it looks like any normal program, except you're using <- to define variables rather than =. Can't see how it could be any clearer than that.

Re: Why Maybe Is Better Than Null

#30

Earlier quoted context omitted.

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.

I don't have a whole lot of Haskell experience ... but these "Maybe" unwrapping functions are rare right? Like a null check I'd think that most of the time you make the check when you get the unreliable input or allocation or whatever, and thereafter in the guts of you program you have the certainty that the input has been "checked".

Yes, that's the great thing about Maybe — any code that doesn't need to care about the uncertainty is freed up from worrying about nulls by guaranteeing it won't get one. Most of your functions will usually deal with the unwrapped type, so if you try to pass the Maybe to these functions, the type-checker will say, "Wait, this function isn't expecting a Maybe. You've done something wrong here." So you have to do your "null check" at the point where you get your Maybe, and then you know for certain that the rest of your code won't explode with a NullPointerException or whatever.
Post reply on HN