[erlang-questions] Idiomatically handling multiple validation checks
Oliver Korpilla
Oliver.Korpilla@REDACTED
Wed Dec 7 00:55:26 CET 2016
Hello.
I really like this answer.
Can't say much about Erlang on this one but in most languages exceptions unwind the stack and are really slow. While performance might not be so important in a true error state, the actual example given is nothing such.
Validating data before using it is the bread and butter of any program that wants to be minimally robust. Invalid input is not an error, it's quite normal in many applications - be it entering into a web form or trying or reading a MP3 file with an encoding error. Applications should optimally deal with such scenarios efficiently. And exceptions are inefficient but can afford to be because of the assumption "it's all gone to crap anyway." If invalid input, however, is part of the normal operation of a system (like the Unix shell, also) then it might be wasteful depending on your overall performance constraints. (At least in Java or C++, again not knowledgeable on Erlang exceptions and implementation details.)
>From an earlier post and addressed to that author:
"Absolutely it can be done Haskell/ML way with values wrapped as {ok,_} or {error, _} and returned. This will make beautiful flow and will triple the chain runner function size, or you will have to add an {error, _} clause to each of your handlers. And exceptions still are going to happen, so those have to be caught and wrapped with {error, _} too."
I think there is lack of clarity regarding idiomatic Erlang (as the thread title implies)... What is called the "Haskell/ML way" I see also as the Erlang way. Or the elixir way. Returning {error, ...} and handling that can make good readable code IMO. Exceptions are not meant to reduce code size nor remove case handling. Whenever you raise an exception you lose almost all context of what happened and give minimal information to somebody up the call stack. This "I don't care" style of error handling can be highly problematic and I've run into plenty of situations where the handler of the exception has no idea how to handle it or what went wrong.
The example however, had one nice aspect to its flow. The nested functions for validating one element after another could be written as
input |> check1 |> check2 |> check3
in elixir, and I do love that style (and find nested function calls on results of function calls very messy, syntax-wise).
This whole chain can work nicely and is not bad style. The whole exception handling block around it, however, could be. This is like Java where if the thread dies your application dies with it so you build these hedge mazes of try/catch around everything and sully every function signature with exception declarations. If I run into an unrecoverable error in Erlang I have seen the light of dying and restarting. I don't pretend my dumb program anticipates all future scenarios and have fared really well with fast restart. I do however not use exceptions for recoverable scenarios because there are actually quite few. Since I work with implementing protocols most scenarios end in sending back a message anyway that terminates a scenario. case statements or a separation function head for unhandled scenarios are IMO more readable...
It is really a shame Erlang does not seem to have the cond statement elixir has. It makes the code for validation clear as can be.
You see, each cond statements is evaluated and we only care about the first one returning "true." So, you could write validators returning true or false and do this:
cond do
check1(some_input) -> {:error, ...}
check2(other_input) -> {:error, ...}
...
_default -> fun_for_valid_input(all_input)
end
You then have isolated all validation calls into one function in one place without any nesting or exception handling in a readable way. Each individual check can be written clearly as a separate function returning true on detecting a problem. Everything is very straightforward and should perform well. As an added bonus it has the short-cut semantics of the and statement but is way more flexible - the first true statement exits but with a meaningful value. And the individual condition checks can be _anything_. Hard to beat for this scenario IMO. It's not Erlang but at least Beam...
Oliver
Gesendet: Dienstag, 06. Dezember 2016 um 23:59 Uhr
Von: "Richard A. O'Keefe" <ok@REDACTED>
An: erlang-questions@REDACTED
Betreff: Re: [erlang-questions] Idiomatically handling multiple validation checks
Joe Duffy of Microsoft gave a talk about systems programming in C#.
(He worked on a project that built an operating system + utilities
in C#.) The talk is at
https://www.infoq.com/presentations/csharp-systems-programming?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=presentations_link&utm_content=link_text
He had some interesting things to say about exceptions and errors.
* Exceptions are meant for recoverable errors;
but many errors are not recoverable!
* A bug is an error the programmer didn't expect;
a recoverable error is an expected condition,
resulting from programmatic data validation.
* Treating bugs and recoverable errors homogeneously
creates reliability problems.
* If you’re going to fail, do it fast.
* Exceptions [can] delay the inevitable and invite[] abuse.
* Fail-fast ensures bugs are caught promptly before they
can do more damage.
* In [their] experience, 1:10 ratio of recoverable errors
(exceptions) to bugs (fail-fast).
Apart from that, I really liked zxq9's response.
_______________________________________________
erlang-questions mailing list
erlang-questions@REDACTED
http://erlang.org/mailman/listinfo/erlang-questions[http://erlang.org/mailman/listinfo/erlang-questions]
More information about the erlang-questions
mailing list