Hacker News new | ask | show | jobs
by hamstercat 1703 days ago
The difference between null and undefined in JavaScript is something I wished had never been implemented. Other languages refer to null as their billion dollar mistake, but somehow JavaScript got 2 of them with slightly different but sometime identical behaviour. I would defer to eslint to prevent this particular issue if you care about it, this allows you to set rules in your own code without any impact to the outside world.

I have only seen null vs undefined lead to 2 things in my experience: mistakes and bikeshedding.

6 comments

> Other languages refer to null as their billion dollar mistake

The "billon dollar mistake" as described by Tony Hoare was not nulls per se.

The billion dollar mistake was having a type system where null was a member of every reference type. This does not apply to language like JavaScript without static type checking, and it doesn't apply to type systems like TypeScript where null or undefined have to be explicitly specified as members of a type.

The undefined/null distinction solves an additional problem: In Java you don't know if a value is null because a field wasn't initialized correctly or because it was deliberately set to null. JavaScript allows you to distinguish between these two scenarios.

exactly.. the 'only' billion dollar mistake in JS in regards to null is that typeof null === 'object' => true
It’s not undefined, therefore it’s an object. And because every type can be null, it makes sense that it’s just “object”, not “string” or whatever.
It it just a mistake or oversight in the definition of the language. It doesn't really make logical sense that a null is an object but a string is not an object.

It would kind of make sense in Java, where only object types can be null. But that distinction does not exist in JavaScript.

typeof null should be "null", just how typeof undefined is "undefined"

it is an implementation bug of netscape, null was represented by the zero pointer and objects where tagged pointer with a tag of zero, so when reading its tag null looked like an object.

there are solutions as x == null, x === null, and Object(x) == x allow you to check for null|undefined, null, and object values, but typeof null being "object" is purely a specification bug that it is too late to change.

I've always liked the two-nulls solution in JS. `undefined` is a runtime-generated missing value, whereas `null` is a compile-time author-supplied missing value. In other words `undefined` is a "pulled" missing value, `null` a "pushed" missing value. Any feature can be misused, but having the distinction is certainly helpful.
I'm fond of this distinction as well. One could also parse it semantically as `undefined` meaning "unknown unknown" vs `null` being a "known unknown" (or "this value left intentionally blank").

Where I think it falls down in practice, is that JS still treats undefined as a legitimate pseudo-value, as opposed to a read-only return result for a missing key. So for instance, `x=[0,1]` and `x=[0,1,undefined]` will both return undefined for `x[2]`, and it takes jumping through some hoops to know if that value was undefined on purpose, or if the key is simply not found.

If I had my druthers, attempting to set a value as undefined would either throw a fatal error, or be an alternate syntax to unset a value (such that `x.length` would equal 2 in both examples above).

I agree. I can understand the parent but I like these distinctions and Typescript makes them easier to deal with for me
When people refer to the "billion dollar mistake", they mean the language feature that every value could potentially be `null`, i.e. even if a function returns MyType, it could also return `null`.

TypeScript in strict mode (the default) still has `null` and `undefined`, but not the billion dollar mistake: if you want to be able to pass `null` to a function, you have to mark that parameter as being potentially `null`.

> I have only seen null vs undefined lead to 2 things in my experience: mistakes and bikeshedding.

I disagree, though I think the implementation leaves something to be desired. Primarily, I think there is fundamentally a difference between the value of obj.bar in the following examples that is useful to differentiate between:

{ foo: 'hello' }

{ foo: 'hello', bar: null }

For example, GraphQL makes specific use of this when dealing with input types for mutations: null essentially means "delete this field" while unset means "don't change it".

There is a very good discussion on this topic here, https://github.com/graphql/graphql-js/issues/133 , which goes into the rationale behind it, how it's supported in languages that do NOT differentiate between null and undefined, and how some folks changed their minds on the issue.

Both Flow and CoffeeScript got this right, while TS is slowly dragging its feet towards the right solution: Pretend there’s no difference between them. Your code will be easier to reason about. If you need two different “other values”, use a proper enum / type union / restructure your API.
I disagree. `null` in TypeScript is equivalent to `None` in many other typed languages. `undefined` in Typescript is like null in other languages, with the caveat that if you’re working to transition an untyped codebase and trying to bring types, there may be a useful place for `undefined` in order to express that there is a lack of safety / strict-handling in that area.

I’m still not sure about Error handling, though. Seems feasible that in a fully typed project, any possible unhandled error type could raise a compile error. AFAIK there’s nothing (beyond catch + exhaustive switch) to handle exhaustive error checking in TypeScript, nor is there lib support for handling it either.

Which language has both a "None" and "null"?
Scala, as I recall. It encourages using Options (Some/None), but since it runs on the JVM and will often interop with Java libraries, you can also have nulls.

Not exactly a language design, but an unfortunate reality.

Oh no! Does it not have a type for NonNull references, like Rust does?
Since Scala 3, it can have total static analysis where nulls become a separate type that has to be explicitly declared in type signatures.

So, yes.

javascript, at least, has "undefined" and "null", an infuriating duality of falsiness. PHP also has a notion of not being set as well as being set but null.
JavaScript is what we are talking about in this thread, making the point that JavaScript is similar to JavaScript does not help ;-)