We've all been there. Tireless hours of testing and careful development halted by a mysterious NullPointerException
or similar problem all due to some undefined value. What are we to do?
Whoever came up with null
, None
, nil
, etc. really hated humanity. I get it. We need a value that represents none-existence but isn't there a better way? Let's try skipping null
altogether will lists. I'm going to show some code examples in Javascript since most people here understand it and it's a particularly stupid language given that it somehow justifies having two none-existing values null
and undefined
. Ah, yes, undefined
. The Schroedinger's cat of the Web.
We might encounter the following in the wild:
let counter;
...some code that may or may not define counter...
if ( counter !== undefined && counter !== null ) {
counter++;
}
What a mess, amirite? Some might even say we should be using typeof
to be extra careful but we can remove this whole problem with lists. Here's a basic attempt.
const counters = [];
...some code that may or may not define a counter inside counters...
if ( counters.length >== 1 ) {
counters[0]++;
}
Now our if
statement is a bit simpler but we still have to check before actually performing the operation. Wouldn't it be great if we could just perform the operation without checking for null
or if the containing list is empty? Well, let's see what our good, old friend forEach
can do for us.
const counters = [];
...some code that may or may not define a counter inside counters...
counters.forEach( counter -> counter++ );
And, boom! This operation will never fail! If counters
is empty then the operation will run 0 times. If counters
has 1 counter in it, the operation will run 1 time. Finally, if counters
has n
counters in it, the operation will run n
times.
Amazing! We don't need to check for undefined values anymore. We can just reliably define container lists and run list operations on those lists which guarantees that operations will not throw exceptions when no values are defined.
Top comments (2)
That's actually an interesting solution. Abstracting that array to just a generic wrapper let's say (like the
Nullable
in C# orOptional
in Java) it could work.A few questions though:
.forEach(...).forEach(...)
? Isn't that really difficult to read?let counter = {}
and have to check forcounter.elements
to be instantiated.My rule of thumb here is to never use
null
and simply check forundefined
as my sole "none" value. So that if statement would be reduced to:And, if I know that
counter
has to be an object then I can simply doMost JS programmers would recognize this pattern.
I'm definitely for Generic Wrappers and these can be easily implemented with the above list strategies.
As for
forEach(...).forEach(...)
, that will actually fail sinceforEach(...)
is a consumer function; it doesn't return anything. Instead usemap()
which is the same asforEach()
but it returns a value. I personally like to do stack method chains like so:That style blends well with list method chains, Promise chains and Streams.
I like the
if (counter)
style but this isn't going to work in every language and my employer doesn't allow it in our JS code. We have to always use the double check unfortunately.