Live data from Hacker News

Why Maybe Is Better Than Null

nickknowlson.com

31–40 of 133 posts

Re: Why Maybe Is Better Than Null

#31

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".

The real trick is that, conceptually, these are not really "unwrapping" functions--instead, they're "propagating" functions. All they do is take Maybe values from deep inside your computation and string them through to the outside.

In practice, this means that you write a decent part of your program using these techniques, which creates a block of code that produces a Maybe value after taking a bunch of Maybe inputs. Then you only use a case statement at the very end, when you need to plug the Maybe value back into normal code.

All these functions are useful for one particular case: you don't know what to do with a Nothing value, so if you see one anywhere, you just pass it on: your final result is Nothing. That pattern just turns out to be very useful.

Re: Why Maybe Is Better Than Null

#32

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".

They are pretty rare. Very few functions actually want to use nullable-arguments. Another reason why nullable by default is a bad idea.

Re: Why Maybe Is Better Than Null

#33
post #23

Earlier quoted context omitted.

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. *…

Is that C++? Just use a reference if you want a pointer which asserts it can't be null.

Re: Why Maybe Is Better Than Null

#34

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've worked on a lot of legacy Java code where these kind of null checks cause problems. The end up confusing things in corner cases.

You should verify arguments at a top level, then let the code underneath blow up with a NullPointerException if something unexpected happened. Your stack trace will point at where the problem lies.

I find for some reason that a lot of people want to use null instead of empty lists where you'll end up with this ugliness:

    if (list != null) {
        for (Thing t: list) {
            processThing(t);
        }
    }
Instead of just passing in a Collections.emptyList() instead.

Re: Why Maybe Is Better Than Null

#35
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 was a poor choice. The local “a” shadows the parameter “a”. You can of course write:

    addM :: Maybe Int -> Maybe Int -> Maybe Int
    addM ma mb = do
      a 
As an aside, the inferred type would be much more general, because (+) works on any number and do/return work on any monad:

    addM :: (Monad m, Num a) => m a -> m a -> m a
Which means you could use it like this:

    addM (Just 5) (Just 10) == Just 15
But also like this:

    addM [1, 2] [4, 8]
      == [1 + 4, 1 + 8, 2 + 4, 2 + 8]
      == [5, 9, 6, 10]
Or like this:

    addM (Right 42) (Left "NaN") == Left "NaN"
And in many more interesting ways. :)

Re: Why Maybe Is Better Than Null

#36
Does that article title pass a type checker? How can you compare a type (Maybe) with a value (Null)?

Is this instead arguing Maybe vs pointers? No, that can't be right; pointers are just type-safe as Maybe, albeit less general.

I guess it's a dynamic vs static typing argument in disguise?

Re: Why Maybe Is Better Than Null

#37
post #31

Earlier quoted context omitted.

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".

The real trick is that, conceptually, these are not really "unwrapping" functions--instead, they're "propagating" functions. All they do is take Maybe values from deep inside your computation and string them through to the outside. In practice, this means that you write a decent part of your program using these techniques, which creates a block of code that produces a Maybe value after taking a bunch of Maybe inputs.…

>That pattern just turns out to be very useful.

Like NaN, it can be hard to track down where things went wrong.

Re: Why Maybe Is Better Than Null

#39
post #33
post #23

Earlier quoted context omitted.

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. *…

Is that C++? Just use a reference if you want a pointer which asserts it can't be null.

It's Java ;P I haven't used C++ in a long time. But you are correct a reference does exactly what he wants.

For anyone who needs to look it up like me: http://en.wikipedia.org/wiki/Reference_(C%2B%2B)

Re: Why Maybe Is Better Than Null

#40
post #29

Earlier quoted context omitted.

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.

Except that what it looks like isn't actually what it's doing (made even clearer by the a I like the Maybe concept and non-nullable types; I just think being able to overload operators like "=" and ";" in C++ and Haskell is optimizing writability over readability and in most cases, readability is by far the more important attribute.
Post reply on HN