I'd like to discuss two things about your proposal:
- first, the associativity of the operator
- secondly, a defense against the top to bottom direction
(warning, long message incoming! )
[ Also, after posting this message, I realized the term "associativity" was not quite the right one to describe what I meant! Please have a look to this following post ]
Discussion about associativity
(here, I'm keeping the direction from bottom up, as you proposed, so that we can easily discuss one thing at a time)
First, I find problematic that this operator does not behave the same way depending on where it is called.
Taking your example:
const chain = globalErrorHandling
|< erroneousFn3()
|< erroneousFn2()
|< erroneousFn1()
we have:
- if the L.H.S is a function: return its R.H.S, or call its L.H.S if an error was thrown
- if the L.H.S is anything but a function: return the R.H.S, or return the L.H.S if an error was thrown
or, maybe in the way you thought about it:
- for the first time the operator is called in a chain: return its R.H.S, or call its L.H.S if an error was thrown
- for all the other times: return the R.H.S, or return the L.H.S if an error was thrown
I'm not aware of any other javascript operator (or in any languages) that are not associative, like the one you're proposing. I also think it would be way too confusing to be actually implemented some day in the language.
In my opinion, it would be way more consistent that the |<
operator always behave in the same way, by always expecting functions:
const chain = globalErrorHandling
|< err => erroneousFn3()
|< err => erroneousFn2()
|< err => erroneousFn1()
There is no longer a distinction between the first operand of the chain and the other, the operator is now fully associative, everything is treated the same way.
Also, in that way, we could even have a finer error handling all the way up.
Side note: desugaring the syntax
If you're still with me, with this new behavior, this simpler example:
const chain = errorHandler |< erronousFn();
would desugar to something like:
const chain = (() => {
try {
errounousFn();
} catch (err) {
errorHandler(err);
}
})();
so our example:
const chain = globalErrorHandling
|< erroneousFn3
|< erroneousFn2
|< erroneousFn1
would desugar to this pyramid of doom:
const chain = (() => {
try {
return (() => {
try {
return (() => {
try {
return (() => {
try {
return erroneousFn1();
}
})();
} catch (err) {
return erroneousFn2();
}
})();
} catch (err) {
return erroneousFn3();
}
})();
} catch (err) {
globalErrorHandling();
}
})();
Discussion about the direction of the flow
I persist to think that top to bottom (and also left to right) is better in javascript. The error upwards propagation will occur during runtime, but as we write and read the code, everything will always be top to bottom.
Like when you explain in your proposal,
we first have erroneousFn1
, then erroneousFn2
, etc. Because this is how we understand what is going to happen, and I think the same way of thinking shoud be reflected in the shortened syntax
This makes even more sense when every operand has to be a function, as there is no distinction to be made between the first operand and the others anymore.
Also, it would allow using this operator alongside the pipeline |>
operator, which would not be the case if it was still working from bottom up:
// Some function definition
const filter = () => { /* ... */ };
const map = () => { /* ... */ };
const finalizeOrSmth = () => { /* ... */ };
const handleMidwayError = () => { /* ... */ }
const value = data
|> filter
|> map
|^ handleMidwayError
|> finalizeOrSmth
|^ () => []; // If everything fails, at least return an empty array
// This would desugar to
const value = (() => {
try {
return finalize((() => {
try {
return map(filter(data));
} catch (err) {
return handleMidwayError(err);
}
})());
} catch (err) {
return [];
}
})();
I personally find this last example very elegant, but I know this is going a little different from your original idea. Also, my opinion is definitely not the only one that counts here, so do not hesitate to continue the discussion, and tell what you think about it