Socrates as soon as stated “the unexamined life shouldn’t be price dwelling.” He was instantly sentenced to dying afterwards.
I, too, typically discover myself analyzing the trivia of programming languages. Fortunately, I’ve not been put to dying for it (but).
After spending greater than a decade honing my Android improvement expertise, I’ve lately switched again to my first foray into skilled improvement, JavaScript. It has lots to look at, and very like Socrates, I’ve many, many questions.
At present, let’s take a look at a seemingly easy query: how do I signify absent knowledge in operate returns?
Suppose I’ve acquired a operate that queries the database for Foo
:
async operate getFoo(id: string): Foo | ??? {
const rows = await question(/* ...some SQL... */)
if (rows.size > 0) return rows[0]
else return ???
}
When Foo
shouldn’t be discovered, what do I return?
For no matter motive, JavaScript offers two choices right here: null
and undefined
. There are refined 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 prefer to reply a extra basic query: who cares?
On its face, this drawback feels fairly dumb. null
and undefined
each imply roughly the identical factor, simply return no matter you’re feeling like, proper? It does not actually matter, so you’ll be able to leverage the vibes as an alternative of your mind.
These kinds of selections come up all over the place: in languages, frameworks, APIs, and even your personal codebase. Conditions the place there’s a couple of strategy to do one thing, nevertheless it’s not all the time clear which method is healthier 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, whenever you research a seemingly arbitrary selection, you typically come out with some actual enlightenment. Maybe the selection appeared arbitrary at first, however via cautious research, you notice there are compelling causes to make use of one methodology 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 finest to cut back the paradox. If it have been apparent what the correct reply was, everybody would do the correct factor and never spend any additional time fascinated about it. However when there’s no clearly appropriate reply, you must 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 endless dialogue of tabs vs. areas). If we are able to give you a well-reasoned nudge in a single path, we are able to spend much less time stressing about it going ahead.
Lastly, typically these questions simply drill their method into my head and I can’t get them out till I’ve a solution. That’s a private drawback 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 potential to write down a codebase that solely makes use of null or undefined? That might be awfully handy (which is why nearly 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”, at the least for many codebases. I’ll summarize the argument right here:
-
It’s straightforward to rule out a codebase that solely makes use of
null
as a result of it’s unimaginable 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 potential to solely use
undefined
however solely in slender circumstances. For instance, TypeScript’s codebase has no nulls. Nevertheless, for those who use JSON or rely on third get together libraries you open your self as much as the potential for utilizing nulls (since each may give you nulls anytime).
It’s price pursuing an undefined
-only codebase, however could also be unimaginable for you. For my very own use case, I should take care of nulls, so I need to scratch this utopian thought.
Can we reply this query by shifting our perspective to that of the buyer? How will they react to receiving a null
vs. undefined
?
The annoying factor about being a client is you received’t all the time know for those who’re getting again null
or undefined
, so you must deal with each circumstances.
How will we if-check “not null and never undefined”? This 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 of thumb in opposition to utilizing!=
if (!isNil(myVar)) {}
(through lodash) works!
Of all these choices, if (!isNil(myVar))
works finest. It’s succinct and kind inference nonetheless works. And for those who’re allergic to dependencies, you’ll be able to write your personal 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 may wish to ultimately attempt to go for an undefined
-only codebase.
tl;dr
My private conclusion:
- Symbolize absent knowledge with
undefined
. - Use
isNil(xyz)
for null checks.
I don’t really feel very hot and fuzzy about my conclusions, however I suppose that’s simply the way it goes whenever you’re working with JavaScript.