principle of least surprise

Martin Bjorklund mbj@REDACTED
Mon Nov 21 15:19:22 CET 2005

After the obfuscation contest we now know that parentheses are
important in guards...

I have a datatype foo which is either an atom or a tuple of size 2.

It would be nice with a macro to test if a certain value is a foo,

  -define(is_foo(X), (is_atom(X) or (is_tuple(X) and (size(X) == 2)))).

Then I could use this test in guards, 

  f(X) when ?is_foo(X) -> yes;
  f(X) -> no.

Isn't this reasonable?  Anyone can read and understand this code.

The problem is that this won't work; if I call f(foo) it will return
no.  The reason is that all expressions in my guard will be evaluated,
and that failure in a boolean expression will fail the guard which is
interpreted as false. (and in this case size(foo) fails).

So I tried some alternatives:

  -define(is_foo(X), (atom(X) or (tuple(X) and (size(X) == 2)))).

not that I thought that this would work, but it won't even compile.
Why do we have atom/1 and is_atom/1???

And I know that this one doesn't work.

  -define(is_foo(X), (is_atom(X) orelse (is_tuple(X) andalso (size(X) == 2)))).


Maybe we shouldn't be allowed to write code like this?  No...

My radical suggestion is:

  o  make sure or,and  etc has precedence over ==,/= etc
     (like orelse/andalso)
  o  _remove_ orelse/andalso completely from the language
     (what's the probability of that?)

And then I think (size(X) == 2) should be false if X is not something
you can do size on.  But that's probably out of the question.


More information about the erlang-questions mailing list