Hacker News new | ask | show | jobs
by z3t4 2015 days ago
Why is null/undefined bad?
7 comments

While I'm sure they're are good academic arguments around why null is not a great language feature, I think the simplest way to explain the problem is to point to the number of bugs, incidents, outages, failures, that all seem to be related to it. Billions of dollars have been lost to null.

You cannot ask for perfect programmers who will never slip up. We're humans. People make mistakes, forget to check for null. So why not instead just make these kinds of issues impossible? Let the build process look for the mistake and block you from making it.

Because it’s very easy to write code that fails to check for null or undefined, which usually leads to errors since subsequent code often expects to find a non-null and non-undefined value.

The beauty of a type checker here is that it can check to make sure you properly handle the nullable/undefinable type.

There’s another approach - where null takes on contextual meaning.

   List<Integer> f = null;
   f.add(1);
This is clearly a NullPointerException in Java but in a language with Nil punning, f is automatically a list containing 1.

    (conj nil 1)
    ;;=> (1)
Sure, I’m not asserting it’s the only way to handle nulls.

That said, for me personally, nil punning is uncomfortably close to the kind of weak typing (like in traditional JS) that can be catastrophic in large code bases.

However, I’ve never worked with a large code base in a Lisp - whereas I have with various statically-typed functional and non-functional languages - and I find static typing, particularly Option types, very valuable.

> That said, for me personally, nil punning is uncomfortably close to the kind of weak typing (like in traditional JS) that can be catastrophic in large code bases.

I think it would be totally fine and safe if “nil” is identical to an empty list in every scenario. In other words, nil is just a shorthand/synonym for an empty list.

Go kind of does that, for example. The only time it’s actually handled differently in my experience is in JSON serialization (which I personally believe was a terrible decision)

> I think it would be totally fine and safe if “nil” is identical to an empty list in every scenario

Yes, I agree. But even in Scheme, that's not the case. I'm not familiar enough w/Go to comment - I'll have to check it out.

I've only ever carved out solutions with stone knives and bearskins. I find stone knives very valuable.
Yes, noted caveman technology Haskell.

In terms of dynamic languages, I’ve also worked with a great deal of Python and JavaScript, with significantly less success on large codebases (which could be due to selection bias, admittedly).

This is also why capital letters are bad.

It's easy to write code which fails to check for a capital letter, which leads to errors when subsequent code requires a lower-case letter.

Capital letters are a billion dollar boondoggle.

It behooves languages to have a lower-case (or non-capital) character type which cannot be constructed with or assigned a capital letter.

I always interpreted that quote to mean that implicit nullability was a mistake. It's fine to have nulls, but not five to have them pop up anywhere randomly.

Capital letters are fine, but not if they randomly pop up when you thought you were only working in lowercase, and now suddenly all your string comparisons need a .toLoweR() on each side of the ==.

In all seriousness, after nulls, I think I've seen more issues caused by case-sensitivity in string comparisons than by any other class of error.

Domain names. Email addresses. Windows UPNs. Windows filenames... All manner of LDAP shit.

Must have been before Unicode. :)
Strict null checks doesn't change the language. It doesn't make the `null` feature of JavaScript go away, it just makes it more explicit in the type annotation. So `null` isn't bad. Languages that don't have `null` have something similar like `Option`.

To me, that helps make the code more maintainable and that's the biggest benefit, even more than catching bugs. The process of maintaining code involves asking questions about the code. "What is this code for?" "Was this code written to handle <edge case>?" "Can this value, sent to me from another part of the system I'm not familiar with, ever be null?"

In a strict null check world, you can answer the last question with confidence just by looking at the type signature. Without strict null check, the types don't tell you anything about whether a variable can be null, so figuring that out can be anywhere between a distraction to a huge endeavor.

It isn't bad per-se. The bad thing is when it would be a bug if a value is null, but the language still allows it to be a null.

By verifying that only the values for which it would be valid for it to be null are ever null, you can catch a large category of bugs automatically. You can catch even more bugs if the language forces you to check whether the value is null if you are dealing with a value that is allowed to be null.

It's one of those things that just allows for a lot of lazy code and/or unresolved corner cases.

Newer paradigms do varying degrees of 'forcing' you to handle the situation, with varying degrees of obsessiveness.

I don't quite think any of the solutions are very magically nice ... but we may still be yet one paradigm leap away from something a little more tight. Or, we may just have to live with Optionals forever.

Broadly speaking it's not bad if your null or undefined value has a different type than the shadowed type. The two examples in statically typed languages I can think of is rust and zig; in dynamically typed languages I think of elixir (which assigns it to an atom, and is a crash-fast language), and ruby (nil is it's own class)

Of the languages I have experience with, it's a major problem in C, java, and javascript.

For javascript specifically there is also the issue of falsey discipline; there are a ton of falsey values so you could get tripped up in ways you forgot about when doing a null check.

In JavaScript it's only the value undefined that is interchangeable with null, and only if you use == (two equal signs vs explicit check with three equal signs). eg if(foo==null) so I would say it's extremely rare, but if you are feeling adventurous you could of course write if(foo) and it would match false, undefined, null, 0, empty string, and NaN. Which could be an issue if for example a variable is either a number (0) or null.
In general, it's recommended to use NOT NULL in SQL as well. In practice, NULL causes many SQL statements to require 2 conditionals for logic instead of 1, introducing subtle bugs.

There are exceptions, but I haven't seen many. One useful one is if you want a unique index on a column and you can't use "", you can use NULL.

Another is if you need the full range of a column, plus indicating whether data was supplied or not. I see that more with applications involving money, whereas the empty string works fine for most tables used in SaaS and social applications.

Source: DBA.