

Why we've banned null in our codebase - zazenergy
https://blog.stackmob.com/2013/01/free-yourself-from-the-tyranny-of-null-part-1/

======
jgrahamc
Since he's writing Java, I would rewrite his initial function:

    
    
        public int getIntFromHeader(Request req, String headerName) {
            if(req != null && req.getHeaders() != null) {
                String header = req.getHeaders().get(headerName);
                if(header != null) {
                    try {
                        return Integer.parseInt(header);
                    } catch(Exception e) {
                       return -1;
                    }
                }
            }
            return -1;
        }
    

as

    
    
        public int getIntFromHeader(Request req, String headerName) {
            return Integer.parseInt(req.getHeaders().get(headerName));
        }
    

That way it either returns with a valid int or throws an exception of some
sort (null or otherwise).

Also, -1 is a perfectly valid integer and so this function can't distinguish
between a header with -1 in it and an error. The fact that there's a req !=
null check seems silly. Surely, the caller should be responsible for that and
if they aren't they should get an exception.

~~~
justinsb
My preferred approach here is to have two methods; one that throws and one
that also takes a default value.

If the caller would handle the not-present case by assuming a value then use
the default-value version; if it's an error then use the throwing version.

~~~
prawks
And even in this case, a method full of != null checks seems silly when you
can just catch NullPointerExceptions and return the default, no?

Also, Java is statically typed. If you need such dynamic capabilities, look
elsewhere?

~~~
NateDad
The problem with catching an NPE is that you don't know what was null, so you
can't know if it was expected or not. Was req null? Or was the NPE thrown from
inside GetHeaders()? Or something else entirely?

~~~
prawks
Right, but in the provided example what was null doesn't seem to matter. Only
that there was a null reference.

------
ajross
This seems to be missing the point. There certainly are paradigms (C++ RAII
being the most obvious) where you work with objects or data that can be
affirmatively guaranteed to exist. And those indeed have value and are worth
emulating even in environments that don't natively support them (the linked
article is in Java).

But that has nothing to do with "null". There are _other_ paradigms (linked
lists or weak references, say) where you want the ability to distinguish
between a "valid" object and an invalid/empty/not-present one. And whether you
call this thing "null" or not is just a semantic question. It's no less an
error to operate past the end of the list or try to access an expired cache
empty just because you decided to allocate memory to store it.

~~~
noelwelsh
Nah, that's not the issue. The way the game works is this:

1\. Decide on some property you want the compiler to enforce for you. E.g. I
care about only operating on values that exist.

2\. Encode this in the type system. E.g. use the Option type to distinguish
those values that may not exist (Options) from those that definitely do
(everything else).

It's not about being able to distinguish valid and invalid values, it about
getting the compiler to enforce it for you. This is the real power of modern
type systems -- not bookkeeping to keep the optimizer happy but getting the
computer to check the things you care about.

~~~
NinetyNine
In the specific example of the blog post, an isDefined() is still necessary.
How is `isDefined()` different than `ref !== null`?

~~~
lmm
The difference is that you can distinguish at the type level between values
that could be "null" (Optionals) and values that are never null, and the two
look different from each other. Otherwise you tend to have one of two
problems:

a) Every function checks all its parameters for null, and you do null checks
before calling a method on any object, wasting time.

b) It's down to the programmer to figure out where a null check is necessary
and where it isn't, and they sometimes get it wrong.

(Of course, better code will avoid calling isDefined or get, but even if you
just use it as a like-for-like replacement, using optionals in place of null
can improve your program)

~~~
michaelt
Null checks in java are quite cheap, from what I've read.

If your code doesn't check for a null, JIT adds in an implicit check in case
it needs to throw a NullPointerException. When you put a check in your code,
it knows to eliminate the implicit check.

Putting null checks everywhere does lead to ugly, complicated-looking code
though; it'd be nice if there were a simple syntax for non-null parameters.

~~~
bunderbunder
It's not really about computational expense. It's about making reliable,
maintainable software.

The problem with null is that it's a semantic gremlin. Depending on context it
could mean all sorts of things including but not limited to, "the value has
not yet been set", "the value is undefined", "the value is nothing" or "the
software is broken". Which one of those is the correct interpretation at any
given time is a question that can only really be answered by a programmer with
a good knowledge of the codebase.

Worse yet, even in cases where null isn't a desired behavior it's still
inescapable. If your procedure accepts reference types as parameters, it
doesn't matter if it has no interest in taking null as an argument, or that it
doesn't even make any sense (semantically) for null to be passed as an
argument. It still has to be prepared to be handed null as an argument. At a
language level, there's simply no support for the concept of, "Guys, I really
do need something to go here." Which is simply insane, considering how simple
a concept it is.

In languages that don't have null references, it's not that the various
semantic meanings of null have been thrown out. All that's been removed is the
ambiguity: For each possible (desirable) meaning, a construct is provided to
represent _specifically_ that meaning. Meaning that you've gotten rid of the
problem of programmers having to magically know what null means in that case,
and the worse problem of programmers introducing bugs resulting from them
failing to understand null's meaning in a particular context.

------
paupino_masano
While I agree in theory, boxing a null like that can have severe garbage
collection implications. If every core function that required a simple two or
three state response returned a boxed object then it also adds a requirement
for the GC to "throw away" the object when necessary. The more trash the GC
needs to clean up = the more time the GC uses cleaning up.

I'd be careful - that's all. I've seen systems which have done exactly this
for core pieces of logic and they have suffered miserably during long running
processes.

Mind you I'm referring to Java/.NET here - I'm not familiar with Scala's
subsystem so can't comment on that...

~~~
fusiongyro
The idea here isn't to replace every T with Option[T]. The idea is to locate
the places where incoming data might be absent and handle it there, so that
the other 90% of your code can just use T with wild abandon. Like most
methodologies, if you do it wrong it will be a fiasco and if you do it right
it won't be so bad.

------
ihsw
This seems indicative of the arrow anti-pattern[1] and guard clauses[2][3]
would be preferable to banning null and cluttering your class definitions with
isDefined everywhere.

[1] [http://www.codinghorror.com/blog/2006/01/flattening-arrow-
co...](http://www.codinghorror.com/blog/2006/01/flattening-arrow-code.html)

[2]
[http://martinfowler.com/refactoring/catalog/replaceNestedCon...](http://martinfowler.com/refactoring/catalog/replaceNestedConditionalWithGuardClauses.html)

[3] <http://c2.com/cgi/wiki?GuardClause>

The most important point: handle negative conditions first, so checking for
null first and putting a return statement _right away_ when detected.

~~~
tikhonj
You should look at the second part of the blog post[1]. It shows how to get
around the "arrow anti-pattern" using map, filter, flatMap and for-
comprehensions in Scala. It's actually both simple and elegant! Also not very
hard to understand.

[1]: [https://blog.stackmob.com/2013/01/free-yourself-from-the-
tyr...](https://blog.stackmob.com/2013/01/free-yourself-from-the-tyranny-of-
null-part-2-why-weve-banned-null-in-our-codebase/)

What you're actually doing is using the Option monad in Scala, but the article
doesn't tell you that to avoid scaring you. And it succeeds: the pattern
described in the second part of the blog post is easy to follow and clearly
has no magic.

------
tikhonj
Everybody should read part 2 of this post[1]. That's where all the interesting
things are! I wish they had either not separated out the interesting bits into
a different article or that part 2 was the article on HN.

[1]: [https://blog.stackmob.com/2013/01/free-yourself-from-the-
tyr...](https://blog.stackmob.com/2013/01/free-yourself-from-the-tyranny-of-
null-part-2-why-weve-banned-null-in-our-codebase/)

Essentially, part 2 shows how you can very easily overcome the issues with the
approach in part I using some nice Scala features. You can get elegant code
without sacrificing the more expressive types.

------
evincarofautumn
Option types represent computations that can fail. In order for an option type
to be at all useful, you need to be able to actually _do_ computations: take
an Option<A> and a function A → B, and get back an Option<B>. That’s exactly
what the Functor, Applicative, and Monad instances for the Maybe type in
Haskell do.

Here, you’ve just traded one kind of checking (!= null) for another
(isDefined). This is more type-safe, to be sure, but has a high legibility
cost. There is also no gain in exception safety: NoSuchElementException is not
appreciably more meaningful than NullReferenceException.

~~~
pcwalton
In my experience the legibility cost is more than outweighed by the fact that
Option is only used in a small set of places, rather than implicitly used
everywhere as with nullable references. Because it's only used in a few
places, the use of `.isDefined()` or pattern matching stands out and actually
helps to make the reader aware of where computations could fail.

~~~
evincarofautumn
Sure, it’s certainly better to be explicit. I’m just saying that you can have
explicit checked optionality _and_ safety _and_ legible code.

------
dap
At the end of the day, you can't get away from the fact that arguments and
return values may be NULL or they may not, and if so, NULL is interpreted in a
certain way by the program that depends on the context. Whether these
semantics are documented, enforced by the language, or neither, the programmer
using a function must know them in order to write correct code. The convention
I've worked with is that these semantics are either obvious (because the scope
of a function is small, and it's reasonable to require programmers to examine
the function to see what it does) or documented. Mandating that the basic
types cannot be null and requiring a special null-able type forces programmers
to consider this issue, but if you work with a code base that understands the
above, I'm not sure the trouble and obfuscation is worth it.

There's a history of elevating useful programming patterns (constructors,
generic references, and dozens of other C++ features come to mind) to the
level of being enforced by the language or runtime, and in most of these cases
I've found the cost of doing so (in language complexity and inflexibility) far
outweighs the benefit of preventing programming mistakes.

------
pixie_
I wish more languages treated null like objective-c. Where if a method is
called on a null object, nothing happens and the method returns null. In user
land a 'null bug' in objective-c often results in a feature not responding, as
opposed to the entire app crashing. It's a much better user experience, and I
can write code less paranoid about null values as well.

The car doesn't need to blow up if the air conditioning isn't working.

~~~
Too
Keeping the program running with corrupted data sounds very dangerous and
brittle. Reminds me of php where passing the number 5 or the string "5" into a
function returns the same thing whereas passing the number 0 or the string "0"
can behave completely different. Not caring about what data you have and just
trying to keep running is just sweeping the problems under the carpet and
waiting for them to come bite you when you least expect it.

~~~
pixie_
Is it better for you, or for your user? Are you building a game, a social app,
or space shuttle software? These questions should guide your decision in
language requirements.

------
justinsb
Google provides Optional<T> as part of the Guava library, so this is a fairly
well-known idea. I find it fairly tedious to use though.

The @NotNull annotation seems like it should be the answer, but I don't know
of anyone that uses it. Would love to hear if anyone has figured out how to
get value out of @NotNull!

------
jimmyjazz14
Haskell does this sort of thing in a slightly more elegant manner using the
Maybe monad
[http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Ma...](http://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe)

------
tantalor
> public Option<Integer> getIntFromHeader(Option<Request> request, String
> headerName) {

> We’ve now, strictly speaking, solved our problem

No, now you have two problems. What if request is null?

------
Too
Any language that allows null should also provide a non-nullable type. Kind of
the opposites of C#'s ?-operator that turns non-nullable types into nullable.
In an SQL table it's very natural to choose whether an item is allowed to be
null or not, so why not in a programming language?

It still baffles me why C# and Java does not have this.

At least in C# you can use code contracts to constrain functions to not accept
_"possibly"_ null values. I haven't used this myself but the demos I've seen
look impressive. Anyone got hand on experience of this or similar?

~~~
wsc981
Code contracts might be enforced using assert macros, I guess this would
achieve more or less the same effect, right?

~~~
Too
No. assert() validates at run-time. Contracts at compile-time.

------
devsatish
Was recently working with a mainframe code for an update operation and my code
was sending "NULL" for the last name. Surprisingly there was a person with
NULL as last name (seems it's a valid last name, search facebook or LinkedIn
and you will find tons of them), had to pull my hair when I saw that all the
update transactions are being applied with that particular person's account.

TLDR: Careful, there could be some one with last name or first name = NULL"

------
RyanMcGreal
Banning null doesn't seem to have stopped their site from falling over.

There doesn't seem to be a google cache available.

------
djbender
Google Cache:
[http://webcache.googleusercontent.com/search?q=cache:6CnwYpP...](http://webcache.googleusercontent.com/search?q=cache:6CnwYpPTDSAJ:https://blog.stackmob.com/2013/01/free-
yourself-from-the-tyranny-of-null-
part-1/+&cd=1&hl=en&ct=clnk&gl=us&client=safari)

------
mnarayan01
Title really needs to be postfixed with "in Scala".

~~~
mseebach
That would be a little silly, given how they're doing it in Java. Anyway, the
paradigm translates easily to any OO language.

~~~
mnarayan01
Reading to the bottom and then viewing the subsequent post makes it pretty
clear they are not doing it in Java; hence the need to change the title.

------
chris_mahan
Your codebase is written in COBOL?

------
alxndr
"Error establishing a database connection"

Made me laugh.

