[erlang-questions] The If expression
Henning Diedrich
hd2010@REDACTED
Thu Apr 22 03:08:53 CEST 2010
Hi Richard,
thanks a lot for the lightning-speed & sorrow reply!
Please be gentle, my eyes are sore already :-D
I also realize I was somewhat hysteric, maybe.
Looking for examples now, I found 5 true->nil in a thousands lines. So
maybe that absolves a bit of my guilt of doing imperative code. No
matter, the question remains as sincere as before. That was exactly what
I wanted to address and what the 5 places - given below - totally look like.
>
>> Did anything come from the discussion about the if expression (
>> http://www.erlang.org/pipermail/erlang-questions/2009-January/040808.html )?
>>
>
> (1) The "undocumented?" comment in that article is just plain wrong.
I meant to basically give the head of that related thread.
> (B) General Erlang "style" for 'else' is '; true ->'
It's not hard to get used to. I wasn't going to complain about that
oddity actually, but wondered what to do different, to not have to write
it 'empty' now and then.
Regarding 'have', see below please.
> (C) It has been argued at great length over many years in the
> Software Engineering community that 'boolean' is almost always
> the wrong type to use. In too many situations, it is not clear
> which convention is followed: does 'true' mean connected or
> disconnected? In too many other situations, there are more than
> two possibilities. In this mailing list, the latter case has
> very often been substantiated.
I think it's exactly the (few) cases where 'yes or no' is what matters,
see samples at bottom, thanks.
The rest of the paragraph, I won't dispute. AND I'd happily avoid the
(few) cases left.
>> I remember reading that one-branched ifs shouldn't be necessary.
> (3) It's not that they SHOULDN'T be necessary.
> It's not even the obvious fact that they AREN'T necessary.
> The point is (2,C) that they are often WRONG.
Right, it sure looks like they /are/ necessary, to me. Which /is/ why I
started wondering if I am doing sth. wrong here.
>>
>> Is there a specific tip on how to think differently when one runs
>> into frequently using one-armed ifs? I.e., writing a lot of true ->
>> nil for the empty second branch?
>
> For one thing, this is a clear sign of writing imperative code.
Exactly, that's why I am asking about /thinking/ differently.
> Pure functional languages like Haskell and Clean don't have one-armed
> ifs because every expression has to have a value, and both arms of an
> if have to have values of the same type.
It's funny you say that because it seems like /all/ spots where I ran
into this issue are one of
* output
* message sending
* global names registration
... David's example adds
* creating a connection
... also an external state issue.
All samples seem to be about /creating a side effect/ --- or, under
certain conditions, not creating it.
Is that a legitimate opening for a one-branched if? Exactly for the less
functionally-clean stuff, on Erlang's more practical leanings?
As I said, the rest of the 1000 lines, with ~15 more ifs, didn't need
empty 'else' clauses. Way rare enough to be a non-issue as matter of
style, typing or readability. But for the principle.
>
> The best thing to do is to show us some code and invite us to refactor
> it.
Thanks a lot for the offer! With a tad of context. Sorry if there should
be a typo, I sanitized them to make them more concise.
(1)
print ->
if
% suppress printing the default suite when unused
>>> (Nom == "Default") and (Passed+Failed+Crashed == 0) ->
>>> nil;
% print all other
true ->
echo("~s~n~s ~s - Tests: ~p, Passed: ~p,
Failed: ~p, Crashes: ~p~n~s",
[Line, Nom, Verdict, Passed+Failed,
Passed, Failed, Crashed, Line])
end,
main ! { printed, self() },
suite_loop(Nom, Caller, Sub, Passed, Failed, Crashed);
(2)
verbose_echo(Verbose, Format, Para) ->
% Don't print if verbosity is off (false).
>>> if Verbose -> echo(Format, Para); true -> nil end.
(3)
% If exists, drop old before adding new element
Prev = gl:get(suite, Suite),
>>> if Prev /= undefined -> gl:drop(suite, Suite); true ->
nil end,
gl:add(suite, Suite),
(4)
glist() ->
spawn(fun() -> glist_loop([], nil, nil) end).
glist_loop(List, PrevCaller, Return) ->
% call back to originally caller, to deliver result.
% (so: not on very first call, if no Caller is given, or it
died (?) in the meantime.
if
is_pid(PrevCaller) ->
vecho(?D4, "call ~p ~p", [PrevCaller, Return]),
PrevCaller ! Return;
>>> true -> nil
end,
receive
{ add, Element, Caller } -> glist_loop([Element | List],
Caller, ok);
{ drop, Key, Caller } ->
glist_loop(lists:keydelete(Key,1,List), Caller, ok);
{ get, Key, Caller } -> glist_loop(List, Caller,
lists:keyfind(Key,1,List));
E -> throw(E)
end.
(5)
safe_unregister(Name) ->
Registered = whereis(Name) /= undefined,
>>> if Registered -> unregister(Name); true -> nil end.
Thanks you very much for looking at this!
Henning
More information about the erlang-questions
mailing list