How to handle nested case
Michael Truog
mjtruog@REDACTED
Mon Sep 20 04:05:33 CEST 2021
If (try) catch is used that means the source code will not be
referentially transparent (it will be impure) because any of the three
functions may also throw. That makes the approach an anti-pattern,
something to avoid to promote code that easy to inline, optimize, test
and understand.
On 9/19/21 5:32 PM, Richard O'Keefe wrote:
> What is wrong with 'try'?
>
> ok({ok,R}) -> R;
> ok(E) -> throw(E).
>
> try
> Server = ok(get_radius_host()),
> Port = ok(get_radius_port()),
> Secret = ok(get_radius_secret),
> {ok,{Server,Port,Secret}}
> catch throw:E ->
> E
> end
>
> WARNING: UNTESTED CODE.
>
> I'd be inclined to do something slightly different:
>
> ok({ok,R}, F) -> F(R);
> ok(E) -> E.
>
> ok(get_radius_server(), fun (Server) ->
> ok(get_radius_host(), fun (Port) ->
> ok(get_radius_secret(), fun (Secret) ->
> {ok,{Server,Port,Secret}}
> end) end) end)
>
> (which is rather like using >>= \x -> rather than 'do' in Haskell).
>
> I would also be wondering whether it is possible for a non-OK result to be
> ambiguous. Are there values for E that could have come from more than
> one of these 'get_*' functions? Might the caller of your code care about
> where the error came from?
>
> I find myself wondering whether a simple
> {ok,Server} = ...
> {ok,Port} = ....
> {ok,Secret} = ...
> might not be the most idiomatic "let it crash" Erlang way of all.
>
> There is some important context missing here.
> * Why isn't "let it crash" the right answer here?
> * Why should the caller be told that an error occurred but
> in a possibly ambiguous way?
> * Is there no other validation to be done?
> * What do the surrounding comments say?
>
> On Sun, 19 Sept 2021 at 08:50, Gian Lorenzo Meocci <glmeocci@REDACTED> wrote:
>> Hi,
>> I have a function like this:
>>
>> get_nas_from_conf() ->
>> case get_radius_host() of
>> {ok, Server} ->
>> case get_radius_port() of
>> {ok, Port} ->
>> case get_radius_secret() of
>> {ok, Secret} ->
>> {Server, Port, Secret};
>> E -> E
>> end;
>> E ->
>> E
>> end;
>> E ->
>> E
>> end.
>>
>> Which is the best way to write this kind of function?
>>
>> I'd like to have a with operator like in Elixir, to rewrite my function in this way:
>>
>> get_nas_from_conf() ->
>> with {ok, Server} <- get_radius_host(),
>> {ok, Port} = get_radius_port(),
>> {ok, Secret} = get_radius_secret() ->
>> {Server, Port, Secret};
>> catch
>> {error, _Reason} = E ->
>> E
>> end.
>>
>> Any suggestion?
>>
>> --
>> GL
>> https://www.meocci.it
More information about the erlang-questions
mailing list