Socrates as soon as stated “the unexamined life isn’t value dwelling.” He was instantly sentenced to loss of life afterwards.
I, too, typically discover myself inspecting the trivialities of programming languages. Fortunately, I’ve not been put to loss of life for it (but).
After spending greater than a decade honing my Android improvement abilities, I’ve lately switched again to my first foray into skilled improvement, JavaScript. It has rather a lot to look at, and very like Socrates, I’ve many, many questions.
At this time, let’s have a look at a seemingly easy query: how do I signify absent information in perform returns?
Suppose I’ve acquired a perform that queries the database for Foo
:
async perform getFoo(id: string): Foo | ??? {
const rows = await question(/* ...some SQL... */)
if (rows.size > 0) return rows[0]
else return ???
}
When Foo
isn’t discovered, what do I return?
For no matter motive, JavaScript supplies two choices right here: null
and undefined
. There are delicate distinctions between them, however basically they each signify the absence of information.
Which ought to I exploit? Let’s attempt to reply this query with out consuming hemlock.
So What?
Earlier than we start, I’d wish to reply a extra basic query: who cares?
On its face, this downside feels fairly dumb. null
and undefined
each imply roughly the identical factor, simply return no matter you are feeling like, proper? It would not actually matter, so you may leverage the vibes as an alternative of your mind.
These types of selections come up in all places: in languages, frameworks, APIs, and even your individual codebase. Conditions the place there’s a couple of approach to do one thing, however it’s not at all times clear which manner is best as a result of the choices are so comparable.
Ought to I concatenate strings utilizing +
or string templating? Ought to I exploit a for-loop or a forEach()
iterator? Ought to I exploit tabs or areas?
Right here’s why I give a hoot:
First, once you research a seemingly arbitrary selection, you generally come out with some actual enlightenment. Maybe the selection appeared arbitrary at first, however by cautious research, you understand there are compelling causes to make use of one technique or one other. For instance, I investigated properties vs. features in Kotlin and got here out with a deeper understanding of val
. My preliminary (naive) understanding equated val
with “immutable” when it really simply means “learn solely”, and all my future work with class properties was extra nuanced due to my analysis.
Second, the extra ambiguous a selection is, the longer individuals spend time on it, so it’s greatest to scale back the paradox. If it have been apparent what the proper reply was, everybody would do the proper factor and never spend any additional time eager about it. However when there’s no clearly appropriate reply, you need to cease and suppose. And when discussing ambiguous selections, oftimes all you’ve acquired are private opinions, and opinion-based arguments are pointless and infinite (see: the unending dialogue of tabs vs. areas). If we will provide you with a well-reasoned nudge in a single route, we will spend much less time stressing about it going ahead.
Lastly, generally these questions simply drill their manner into my head and I can’t get them out till I’ve a solution. That’s a private downside and applies on to the null
vs. undefined
dilemma (which, imagine it or not, I have been ruminating upon for years).
Alright, Let’s Debate
Let’s get again to the query at hand: coming to a conclusion on utilizing null
vs. undefined
(hopefully with out getting canceled on Hacker information for having imperfect ideas).
My first angle of inquiry: is it attainable to put in writing a codebase that solely makes use of null or undefined? That may be awfully handy (which is why virtually each different programming language solely has one null!). Sadly, a fellow sophist already dug into this concept and got here up with the reply “no”, a minimum of for many codebases. I’ll summarize the argument right here:
-
It’s simple to rule out a codebase that solely makes use of
null
as a result of it’s inconceivable to get away fromundefined
. It’s the worth that properties begin with earlier than initialization, and it’s returned by many core JavaScript features (e.g.Array.discover()
). -
It’s attainable to solely use
undefined
however solely in slender circumstances. For instance, TypeScript’s codebase has no nulls. Nevertheless, if you happen to use JSON or rely on third social gathering libraries you open your self as much as the potential for utilizing nulls (since each can provide you nulls anytime).
It’s value pursuing an undefined
-only codebase, however could also be inconceivable for you. For my very own use case, I must take care of nulls, so I have to scratch this utopian concept.
Can we reply this query by shifting our perspective to that of the patron? How will they react to receiving a null
vs. undefined
?
The annoying factor about being a shopper is you received’t at all times know if you happen to’re getting again null
or undefined
, so you need to deal with each instances.
How can we if-check “not null and never undefined”? Here is a bunch of how, most with drawbacks:
if (myVar !== undefined && myVar !== null) {}
is simply too verbose.if (myVar) {}
coerces additional values (“”
and0
are additionally false).if (myVar != null) {}
breaks the rule towards utilizing!=
if (!isNil(myVar)) {}
(through lodash) works!
Of all these choices, if (!isNil(myVar))
works greatest. It’s succinct and sort inference nonetheless works. And if you happen to’re allergic to dependencies, you may write your individual isNil()
.
As a result of shoppers must be defensive, it doesn’t matter whether or not I return null
or undefined
. That stated, I discover it revolting that typeof null === ‘object’
, so my choice is to return undefined
. Plus, that selection helps out anybody who would possibly need to finally attempt to go for an undefined
-only codebase.
tl;dr
My private conclusion:
- Signify absent information with
undefined
. - Use
isNil(xyz)
for null checks.
I don’t really feel very warm and fuzzy about my conclusions, however I suppose that’s simply the way it goes once you’re working with JavaScript.