[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 -> ...

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 -> ...

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

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