[erlang-questions] The If expression
Richard O'Keefe
ok@REDACTED
Fri Jan 23 03:54:35 CET 2009
On 2 Jan 2009, at 9:14 am, Fredrik Svahn wrote:
> In addition to the above (which is kept for backwards compatibility) I
> suggest adding an alternative form with the following syntax:
>
> if Expression -> Body else -> ElseBody end
>
> which should act as syntactical sugar for the more clumsy and
> unintuitive:
>
> case Expression of
> true -> Body;
> _Else -> ElseBody
> end
>
I'm sorry for the late reply, but December/January is the
long holiday in New Zealand, and I only got back yesterday.
This is a very bad idea because
- It would give us two very *different* conditional structures
with the *same* keyword, where it is hard to tell which one
was intended until several lines later.
- 'if' isn't actually all that rare. In some code I wrote last
year, I find one 'if' for every four 'case's. The OTP sources
have 1 if/10 case, which is less common, but not _that_ rare.
If the old sense of 'if' were rare, we could probably live with
the confusion.
- The new syntax is not consistent with Erlang "style", which
expects multiple arms as a matter of routine (like the Fortran,
Ada, Eiffel, Algol 68 "block if" constructs, but without an "else").
- As a result the new syntax is rather inconvenient. The majority
of my existing uses of 'if' have more than one arm, so would need
nested new-'if's. It's hard to see that as an improvement.
> My hope is that with this improvement 'if'-statements would be the
> recommended choice for expressions evaluating to a bool()
It would not be an improvement.
Such expressions should be avoided, not canonised.
> The proposal would address two of the problems with the current
> syntax:
>
> 1. Today only guards are allowed, not full expressions. For instance,
> today it is NOT ok to write:
>
> if erlang:system_info(smp_support) -> init_smp();
> true -> init()
> end.
>
> which many believe is a rather serious limitation of the usefulness.
And many don't. In fact this is an excellent example of what's
wrong with Boolean functions. The interface *should* have been
something like
case erlang:system_info(smp)
of not_supported -> ...
; supported -> ...
end
and other values are imaginable: smp support might have been compiled
in, but not actually useful because only one core is available. So
maybe the interface should have been
case erlang:system_info(smp)
of not_supported -> ...
; interfaces_supported -> ...
; functional_and_useful -> ...
end
Indeed, if I wanted to know whether to set up for SMP, I would
probably use system_info(multi_scheduling) instead:
case erlang:system_info(multi_scheduling)
of disabled -> no SMP or only one scheduler
; blocked -> there are multiple schedulers and all
but one of them are blocked
; enabled -> multiple schedulers are really available
end
About 40 years ago when enumeration types were introduced it
was pointed out that people over-used Boolean. I've been guilty
of that myself. In Erlang, our aim is to write reliable and
maintainable software. We shouldn't regard it as a PROBLEM
that Boolean expressions are hard to use, we should regard it
as a heaven-sent OPPORTUNITY to critically, and I really do mean
SERIOUSLY critically review all uses of Boolean to see whether
they are really appropriate. My own experience is that in the
majority of cases they are not. (My use of 'if' is almost
entirely arithmetic comparisons.)
> 2. At least of of the guards have to evaluate to true, otherwise a
> runtime error will occur. This leads to unintuitive constructs like:
>
> if Bool -> do_true();
> true -> do_false() end.
>
> Which could be replaced by a more intuitive:
>
> if Bool -> do_true() else -> do_false() end.
It may be more FAMILIAR, but that doesn't mean 'else' is a good
thing. I know that writing '; true ->' is a very easy way to get
'else' in Erlang, but we have a couple of decades of psychology-
of-programming results to show that it's a bad idea. I have
started to replace by
if X > Y -> a() if X > Y -> a()
; true -> b() ; X =< Y -> b()
end end
if X > Y -> a() if X > Y -> a()
; X < Y -> b() ; X < Y -> b()
; true -> c() ; X ==Y -> c()
end end
which I find mildly annoying when _writing_ the code
but enormously helpful when _reading_ it.
This is one reason why I regard a proposal to add 'else'
to Erlang as a bad idea.
> An open question is if it should also be allowed to have expressions
> without an 'else' clause, as proposed by Damien Katz, i.e.:
>
> if Expression -> Body end
Obviously not, because
if Guard -> Body end
is already legal Erlang syntax.
> Which might be useful in some cases, e.g.
>
> if Logging -> log:write("Aiee") end,
Dijkstra's "A Discipline of Programming" gives arguments against
using one-armed ifs in imperative code. In a mostly functional
language it's even worse. Erlang gets this *right*: if you don't
say what to do in some case, then a situation has arisen that
your program does not handle, and the right answer is an exception.
> In this particular case returning false might seem like a good idea,
> but in other cases e.g. an empty list might be just as natural. I am
> just not sure how to apply the rule of least surprise to this...
The rule of least surprise has a corollary:
if there ISN'T a least surprising result,
there is no result (that is, there is an exception).
More information about the erlang-questions
mailing list