[erlang-questions] comma vs andalso

Richard O'Keefe ok@REDACTED
Wed Jul 8 03:59:35 CEST 2009

On Jul 7, 2009, at 4:16 PM, Andrew Thompson wrote:
> I found your explanation a *lot* clearer and even learned something
> reading it, so I'd definitely agree that it's an improvement.

> I'm still unclear as to where 'andalso' differs from a comma though,  
> how
> is
> true, false.
> any different from
> true andalso false.

First, some historical background.
Erlang was influenced by Prolog via Strand-88.
(By the way, does anyone have a Strand manual they don't want?)
In Prolog, there is one and only one way to get and-then (,)
and one and only one way to get or-else (;).  To oversimplify,
     <disjunction> ::= <conjunction> {';' <conjunction>}...
     <conjunction> ::= <primary> {',' <primary>}...
     <primary>     ::= ['\+'] ( <call> | '(' <disjunction> ')' )
     <call>        ::= <atom>['(' <arguments> ')']
One of the things I've left out of that is infix, prefix, and
postfix operators.  So something like

	cousin_sibling_or_self(X, Y) :-
	    ( father(X, P) ; mother(X, P) ),
             ( father(Y, Q) ; mother(Y, Q) ),
	    ( father(P, G) ; mother(P, G) ),
	    ( father(Q, G) ; mother(Q, G) ).

is possible, where "or" is nested inside "and".

Let's return to Erlang.

This syntax was adopted for Erlang guards, *ALMOST*.
(It was also adopted for Erlang function bodies, almost.
  The C-like use of comma in Erlang expressions is rooted
  in Prolog's comma, not C's.)
The *ALMOST* part is that Erlang does not allow nesting.
You cannot write

	f(X, Y) when (X == 1 ; X == 2), (Y == 1 ; Y == 2) ->

You aren't even allowed to write (GE1,GE2),GE3 but *must*
write GE1,GE2,GE3.  Nor may you write G1;(G2;G3).  Weird.
This has never made sense to me.  Such combinations are
perfectly meaningful, and allowing them would make the
definition of some guard macros considerably easier.

The obvious thing to do is to remove this arbitrary

That's not the path Erlang took.  (Honestly, you couldn't
make this stuff up.)  Instead, *new* operators 'andalso'
and 'orelse' (copied from SML, which is a fine language
with some fine compilers) were added.

Most of the time, you can use 'andalso' and 'orelse' in
a guard, where you would have used ',' and ';'.  "Most of
the time" means "when under the normal rules of evaluation
you would certainly not have had an exception."

Let's take two apparently similar functions:

f(X) when is_atom(element(3, X)) ; true -> 42.

g(X) when is_atom(element(3, X)) orelse true -> 42.

By actual test, f(99) -> 42.
By actual test, g(99) -> a function_clause exception.

That is, in a guard, an expression using 'andalso' or
'orelse' is still an expression, and if an exception
occurs in the left-hand operand, the whole expression
is still skipped.

The thing is that 'andalso' and 'orelse' can be used in
any expression, not just guards.  Erlang is treating
them in guard expressions exactly the same way that it
treats them in any other expressions.  And that's
_different_ from the way ',' and ';' are treated when
there's an exception.

I conclude that
(1) you had best be EXTREMELY cautious about using 'andalso'
     and 'orelse' in guards; they are NOT drop-in replacements
     for ',' and ';', and
(2) it is long past time that Erlang allowed nested use of
     ',' and ';' in guards.

More information about the erlang-questions mailing list