Erlang is getting too big
Richard Carlsson
richardc@REDACTED
Tue Oct 14 12:31:30 CEST 2003
On Tue, 14 Oct 2003, Bengt Kleberg wrote:
> Thomas Lindgren wrote:
> ...deleted
> > Here's another part that could stand cleaning up:
> >
> > - guard syntax 1: "," and ";"
> > - guard syntax 2: "and", "or"
> > (are they there anymore?)
> > - expression syntax 1: "and", "or"
> > - expression syntax 2: "andalso", "orelse"
> >
> > All of them working somewhat differently.
>
> oops. what is the difference between ',' and 'and'? and ';' and 'or'? i
> have been using them to mean the same thing.
>
> eiffel has 'andalso' and 'orelse'. the only :-) people that finds 'and'
> and 'or' strange are the ones that has a c background.
Perhaps the most complicated part of the Erlang language are the clause
guards. They are a mess, although we've tried to clear up a few things.
1. Guards are comma-separated sequences (conjunctions) of "tests",
i.e., the commas mean logical "and". (So far so good.)
2. Later, it was added that you could have alternative lists
of tests, if you separated them with semicolon as in
"t01, t02, t03; t11, t12, t13; t21, t22, t23 ->"
(a disjunction of conjunctions.) So, the semicolons mean
logical "or" in this context. (This addition was probably
one of the less motivated ones. I've never used it myself.)
3. A "test" is either a comparison "X == Y", "X > Y" etc, or
a call to a built-in test function like "integer(X)" or
"float(Y)". (I.e., it is not just any boolean expression.)
4. Guard tests have a separate name space! "integer(X)" above
is not defined outside guards, so you can't write:
Bool = (f(X) and integer(Y))
in normal Erlang code - unless you define "integer/1"
yourself. (But you can't override the tests used in guards.)
The test "float(X)" overrides the built-in typecast function
of the same name. You _can_ write the following:
Bool = (f(X) and float(Y))
but you might be surprised when "float(Y)" does not return a
boolean.
5 The subexpressions of guard tests are "guard expressions",
which are a limited subset of normal expressions. Basically:
variables, constants, operators and calls to a subset of the
"automatically recognized" BIFs are allowed, but nothing else.
6. Guard tests are implicitly "wrapped in a catch", so that if
a subexpression crashes (the tests themselves can't crash),
they quietly evaluate to "true" instead. (Thankfully, the
number of programmers crazy enough to actually make use of
this "feature" is very small. I have not seen it used in OTP
and I would like to have it removed from the language.)
7. The boolean operators "and" and "or" (and "not" and "xor")
have been in Erlang quite a while, but were defined to be
strict, i.e., always evaluate both arguments. Furthermore,
they could originally not be used anywhere in a guard(!).
8. When "and" and "or" were eventually allowed in guards, they
actually got the same semantics (within guards) as "," and
";" respectively, since guards cannot have side effects
(and thus it does not matter if you use strict evaluation or
not, space/time aside). But there is no point in using and/or
instead of comma and semicolon unless you like longer lines.
Stick to the normal separators. It's just in subexpressions
that you might use and/or/not/xor once in a blue moon.
9. 'andalso' and 'orelse' (the non-strict versions of 'and' and
'or' can be useful for avoiding deep nesting of case
switches`, and can make the code much more concise. For
example:
case f(X) of
true -> true;
false ->
case g(X) of
false ->
case h(X) of
true -> true;
fasle -> false
end;
true -> false
end
end
is equivalent to
f(X) orelse (not g(X) andalso h(X))
Now, how long did it take for you to verify that the
first version really implements the second one? What
happens if you misspell 'true' or 'false' somewhere?
(Personally, I'd have preferred 'and' and 'or' to be
defined as non-strict to begin with.)
And now, for 10,000 dollars*:
What does the following do, if X is a floating-point number?
if float(X), (float(X) == true) -> true;
true -> false
end
What we've tried to do in the last years is to make the differences
between normal expressions and guards smaller. It's not easy, as I hope
you can see from the above. It was in order to clear up the confusion
with the guard test namespace that we added the "is_..." versions of the
type tests. These have the same definition everywhere, and you can even
call "erlang:is_integer(X)" if you need to. I think they are a good
thing. It is much easier to say to a beginner "Oh, 'integer(X)' is
old-style - avoid that and use 'is_integer(X)' instead." instead of
trying to explain why he can't write 'integer(X)' in other places than
guard tests.
A new book would certainly be in order, if anyone could find a
publisher.
/Richard
* Altairian dollars.
Richard Carlsson (richardc@REDACTED) (This space intentionally left blank.)
E-mail: Richard.Carlsson@REDACTED WWW: http://user.it.uu.se/~richardc/
"Having users is like optimization: the wise course is to delay it."
-- Paul Graham
More information about the erlang-questions
mailing list