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.
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.
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].
> 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.
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:
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.
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.
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?
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.
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!
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.
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
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}
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.
1. You should probably add that link to your read me:
The implementation uses `Symbol` and [`Proxy`](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?
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.