
Show HN: Nothing.js – A chainable mock object which always returns itself - slmgc
https://github.com/slmgc/Nothing
======
bluepnume
One thing I've been finding increasingly while using Flow in javascript is,
null-pointer exceptions aren't really much of a problem any more.

Where they might have caused a bug, 90% of the time Flow will catch them, and
insist that I do a null check and handle that case.

And when they do crop up, it's usually more of a serious failure that I'm
happy to trigger an exception early, rather than having it propagate further
down the stack by using something like nothing.js. Especially given the list
of gotchas. The fact that `Nothing` is not falsy is really problematic.

I'm pretty convinced at this point that `a && a.b && a.b.c && a.b.c.d` is an
anti-pattern in javascript anyway; if I'm that unsure about the structure of
my data, I have more serious problems than just trying to avoid null pointers.

~~~
lojack
Usually things of form `a && a.b && a.b.c && a.b.c.d` are a sign of a law of
demeter violation. This applies to more than javascript. I view code like this
as a sign that there might be a better way, as opposed to a stedfast rule.
Refactoring to remove these types of violations tends to lead to better code.

~~~
grincraft
Law of demeter applies to code, but in JS the deep property access is actually
done often against data (deserialized JSON).

------
ollerac
If you use Babel 7, you can install a plugin [0] to get the optional chaining
syntax [1] that's currently a TC39 Stage 1 proposal!

[0] [https://www.npmjs.com/package/babel-plugin-transform-
optiona...](https://www.npmjs.com/package/babel-plugin-transform-optional-
chaining)

[1] [https://github.com/tc39/proposal-optional-
chaining](https://github.com/tc39/proposal-optional-chaining)

~~~
samhunta
Yes this is a much better alternative in my opinion.

------
m0meni
Wouldn't this swallow errors that you wouldn't want it to swallow? e.g. you
try to access a property on a value that's null (which you think isn't null),
and instead of getting an error, nothing happens. Idx[0] is a way better
solution to dealing with the boilerplate of checking for null/undefined that
has 0 runtime cost due to being compiled away by babel. It works with type
systems, and you can even use it as a babel macro[1].

With it

    
    
        idx(props, _ => _.user.friends[0].friends)
    

compiles to

    
    
        props.user == null ? props.user :
        props.user.friends == null ? props.user.friends :
        props.user.friends[0] == null ? props.user.friends[0] :
        props.user.friends[0].friends
    

Optional chaining[2] would add this to JS at the language level by using ?. as
the operator.

[0]:
[https://github.com/facebookincubator/idx](https://github.com/facebookincubator/idx)
[1]:
[https://github.com/dralletje/idx.macro](https://github.com/dralletje/idx.macro)
[2]: [https://github.com/tc39/proposal-optional-
chaining](https://github.com/tc39/proposal-optional-chaining)

~~~
slmgc
idx requires a transpilation step.

> you try to access a property on a value that's null (which you think isn't
> null), and instead of getting an error, nothing happens

You can check for Nothing if you know you shouldn't get one. It's not about
swallowing errors, it's about removing try/catch and all this `a && a.b &&
a.b.c && a.b.c()` boilerplate code.

> Optional chaining[2] would add this to JS at the language level by using ?.
> as the operator

But it's not there yet and it will require a transpilation step for quite some
time before all the major browsers will introduce this feature.

Nothing returns "safe" default values instead of null/undefined, which might
come in useful in some cases. Also, it can be used in unit tests to mock some
deeply-nested constructs.

------
TheAceOfHearts
I think this kind of access pattern is typically a code smell. Instead of
carrying around arbitrarily nested values you should try to normalize it into
a known and consistent shape when crossing serialization boundaries.

Proxy pays a big performance penalty, and I doubt it'll be improving any time
soon. In addition, I believe it's not possible to polyfill Proxy. An
alternative could be to just wrap the deep property access in a try/catch:

    
    
        function getQux (input) {
          try {
            return input.foo.bar.baz.qux()
          } catch (e) {
            return null
          }
        }

~~~
afranchuk
Yeah, my first thought when seeing that it uses Symbol and Proxy was that
Proxy can't be polyfilled. But it looks like there's partial polyfills for it:
[https://www.google.com/url?sa=t&source=web&rct=j&url=https:/...](https://www.google.com/url?sa=t&source=web&rct=j&url=https://github.com/GoogleChrome/proxy-
polyfill&ved=2ahUKEwjVptCr5ZfaAhURjlkKHe1MB9sQFjAAegQIBxAB&usg=AOvVaw0nUHNMpcd0EoEqYO_Csr4A)

------
bcherny
This is a really neat idea, and is a lot more ergonomic than nulls or
optionals in JS. Until optional chaining makes its way into the spec [0], this
is the cleanest way I’ve seen to operate on maybe-null values.

[0] [https://github.com/tc39/proposal-optional-
chaining](https://github.com/tc39/proposal-optional-chaining)

~~~
sametmax
It's also hell to debug as it silently always works and propagate.

It's good for unit testing though.

~~~
bcherny
That’s true, but ostensibly you only use it in places where you expect nulls
and don’t intend to debug anything. That’s why Smalltalk, C#, CoffeeScript,
and probably JS and TS soon have null chaining.

~~~
_sdegutis
Objective-C also allows nil to receive messages which then just returns nil
also. I’ve always found this really natural in that you can assume something
is either valid or null and avoid a whole lot of null checks this way. That
said, I’ve never been terribly frustrated by other languages either which
throw when calling methods on null. Maybe it’s because of heavy use of certain
design patterns that make it so it’s never really a surprise?

~~~
sametmax
It also means a chained call with an nil in it still complete from start to
end. So it has additional overhead, and you better not have side effects in
there.

All in all, I'd like to have some kind of "?" operator in Python, I do think
the pros are most of the time greater than the cons.

------
_nalply
Perhaps use the hint parameter of Symbol.toPrimitive() to fix some gotchas
like Nothing + 123 => '123'?

See MDN: [https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Refe...](https://developer.mozilla.org/en-
US/docs/Web/JavaScript/Reference/Global_Objects/Symbol/toPrimitive)

Edit: Won't help, because hint == 'number' is only triggered if used with
unary plus or minus. Disregard this comment.

~~~
slmgc
Nope, hint won't help here as it gets `default` instead of `number`.

------
harunurhan
Interesting project, but I'd stick with idx[0] since I have transpilation
setup most of the time anyway.

Also some of you could be interested in optional.js[1], it's Java's Optional
for js, makes it arguably more pleasant to deal with null values, no help for
chaining though!

[0]
[https://github.com/facebookincubator/idx](https://github.com/facebookincubator/idx)
[1]
[https://github.com/JasonStorey/Optional.js](https://github.com/JasonStorey/Optional.js)

~~~
bcherny
And if you’re using TypeScript, theres also TSOption
[https://www.npmjs.com/package/tsoption](https://www.npmjs.com/package/tsoption)

------
vemv
Ruby equivalent:

    
    
      class Whatever; def method_missing *_; self; end; end
    

Sample usage:

    
    
      irb(main):001:0> Whatever.new.foo.bar.baz - 2
      => #<Whatever:0x007fd7ed0a2a68>

~~~
slmgc
Yep, it's way easier to implement in some other languages. Btw, is it callable
as well? Can you do Whatever.new().foo.bar().baz with it?

~~~
baddox
Nope. Ruby doesn’t support the function call paren syntax for anything other
than methods. You could do stuff like Whatever.new().foo.().bar[] though.

~~~
djur
foo, bar, and baz are all methods here, so you can use parens.

------
grincraft
This would really benefit from adding comments in the 'how to use' code
samples, or at least using standard foos and baars to make it clear what is
user code and what is part of Nothing.js.

For example it is not really clear if 'executeAction()' etc are part of
Nothing.js. I assumed they were, but then the next sample seems to do property
chain traversal transparently, without them.

~~~
slmgc
I agree, examples can be (and will be) improved with additional comments.

------
hath995
I don't think I would be comfortable with production code that swallowed
access errors by providing a guard post value. I feel like that would too
easily slip through in places it shouldn't. To ensure it didn't happen you
would need to include explicit checks everywhere, which sort of defeats the
stated purpose of the library.

However, it is a handy feature for writing tests. I wrote a similar library
for testing called magical-mock based on the python library.
[https://www.npmjs.com/package/magical-
mock](https://www.npmjs.com/package/magical-mock)

------
stareatgoats
Looks elegant, but am not going to sunset the homebaked library solution yet I
don't think, because of the proxy and polyfill overhead, and also because i
prefer to freely assign a specific value if nothing:

TS-like syntax for clarity:

    
    
      Function Nothing(vTestVar:any,  vIfnull:any, sObjPath?: string, bStrict?: boolean) {... return vResultOfCheck}

------
manhinli
Funnily enough, I made something similar a couple of months ago, not as a
replacement for a "nothing" value but as a quick-and-dirty object placeholder
and black box for tracking function calls.

[https://github.com/UQ-eLIPSE/kuro](https://github.com/UQ-eLIPSE/kuro)

------
micimize
This reminds me of my "arbitrary fluent interface" idea
[https://gist.github.com/micimize/064dc637103a6f3651b74380e04...](https://gist.github.com/micimize/064dc637103a6f3651b74380e0419bb2)

------
antoaravinth
It looks very similar to Either functor (left which always return nothing).
Looks cool though.

------
slmgc
Added a FAQ section:
[https://github.com/slmgc/Nothing#faq](https://github.com/slmgc/Nothing#faq)

------
notmarkus
> The implementation uses Symbol and Proxy behind the hood so you might need
> to use appropriate polyfills...

Does anyone know of a working Proxy polyfill? I've never been able to find
one.

~~~
slmgc
I've seen this one: [https://github.com/GoogleChrome/proxy-
polyfill](https://github.com/GoogleChrome/proxy-polyfill)

~~~
sah2ed
1\. You should probably add that link to your read me:

 _The implementation uses `Symbol` and
[`Proxy`]([https://github.com/GoogleChrome/proxy-
polyfill](https://github.com/GoogleChrome/proxy-polyfill)) behind the hood so
you might need to use apropriate polyfills in case you want to support older
browsers._

2\. Personally, I find the name Nothing a bit too long. Why not use a shorter
name like None?

