The thing is if you present code written in the manner described you have to expect to raise some eyebrows because you are ignoring error codes. Obviously you felt the need to do this - however work arounds like this are symptomatic of poor error design.
Defensive programming is messy
So messy in fact that the designers of Erlang invented "Let it Crash" (Programming Erlang 2e, p.88):
Many languages say you should use defensive programming and check the arguments to all functions. In Erlang, defensive programming is built-in. You should describe the behavior of functions only for valid input arguments; all other arguments will cause internal errors that are automatically detected. You should never return values when a function is called with invalid arguments. You should always raise an exception. This rule is called “Let it crash.”
However most runtimes don't have the luxury of letting the process die and having the supervisor deal with the crash (p.199):
If this process dies, we might be in deep trouble since no other process can help. For this reason, sequential languages have concentrated on the prevention of failure and an emphasis on defensive programming.
However there is another point to be made - not all errors are equal. Roughly speaking:
Expected errors. Errors will occur routinely during the operation of the software and therefore should be handled appropriately.
Exceptional errors. Errors that indicate that fundamental assumptions about the software and the environment that it is operating in have been violated. These type of errors cannot be handled at the local scope, so local processing is terminated and the error is passed upwards repeatedly until some kind of sensible compensating action can be taken.
Not all languages have exceptions but they have idioms for exceptional errors. Golang:
// some processingresult,err:=doSomething()iferr!=nil{returnerr}// more processing ...
Rust has the error propagation ? operator.
letmutf=File::open("username.txt")?;
i.e. for Ok(value) the value is is bound to the variable while an Error(error) is returned right then and there.
When a language like JavaScript supports exceptions the rule of thumb tends to be:
Use error values for expected errors.
Use exceptions for unexpected, exceptional errors.
So when we see
const[areas,areasErr]=awaitgetAreas();
areasErr is an expected error and should be handled, not ignored. And just because an error code is returned doesn't necessarily imply that getAreas() can't be a source of unexpected errors. When we see
constareas=awaitgetAreas();
the code is implying that there aren't any expected errors to be handled locally but getAreas() can still be a source of unexpected errors.
there is a bit of a code smell because all errors deemed by getAreas() as exceptional are converted to expected errors at the call site and then are promptly ignored. There is an impedance mismatch between how getAreas() categorizes certain errors and how the code using it treats them. If you have no control over getAreas() then an explicit anti-corruption function (or an entire module for a "layer") may be called for to reorganize the error categorization (and the associated semantics), e.g. :
The thing is if you present code written in the manner described you have to expect to raise some eyebrows because you are ignoring error codes. Obviously you felt the need to do this - however work arounds like this are symptomatic of poor error design.
Defensive programming is messy
So messy in fact that the designers of Erlang invented "Let it Crash" (Programming Erlang 2e, p.88):
However most runtimes don't have the luxury of letting the process die and having the supervisor deal with the crash (p.199):
However there is another point to be made - not all errors are equal. Roughly speaking:
Not all languages have exceptions but they have idioms for exceptional errors. Golang:
Rust has the error propagation
?
operator.i.e. for
Ok(value)
thevalue
is is bound to the variable while anError(error)
is returned right then and there.When a language like JavaScript supports exceptions the rule of thumb tends to be:
So when we see
areasErr
is an expected error and should be handled, not ignored. And just because an error code is returned doesn't necessarily imply thatgetAreas()
can't be a source of unexpected errors. When we seethe code is implying that there aren't any expected errors to be handled locally but
getAreas()
can still be a source of unexpected errors.With this in mind - 4.1.3. Rejections must be used for exceptional situations:
i.e. a promise should resolve to an error value for expected errors rather than rejecting with the expected error. So when we see
there is a bit of a code smell because all errors deemed by
getAreas()
as exceptional are converted to expected errors at the call site and then are promptly ignored. There is an impedance mismatch between howgetAreas()
categorizes certain errors and how the code using it treats them. If you have no control overgetAreas()
then an explicit anti-corruption function (or an entire module for a "layer") may be called for to reorganize the error categorization (and the associated semantics), e.g. :so that the consuming code can be plainly
Compared to the above
comes across as expedient (though noisy) and perhaps receiving less thought than it deserves.