principle of least surprise

Raimo Niskanen <>
Wed Nov 23 08:44:06 CET 2005


>     when is_atom(X) or (is_integer(X) and (X + 5 < 6)) ->

That does not work, at least not in the shell.

1> if is_atom(a) or (is_integer(a) and (a+5<6)) -> true; true -> false end.
false

OTOH:

2> if is_atom(a) or (is_integer(a) and (a<11)) -> true; true -> false end. 
true

works since it does not have to evaluate a+5, which crashes,
causing 1> to fail.

Unfortunately there is no workaround for size(X) that
does not crash for an atom X.

 (Robert Virding) writes:

> Martin Bjorklund wrote:
> 
> >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,
> >e.g.
> >
> >  -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).
> >
> Are you sure that this is the reason? When boolean guard expressions
> were added we defined a strict left to right evaluation jst so we
> could handle cases like this. One of my standard test cases was
> something like:
> 
>     when is_atom(X) or (is_integer(X) and (X + 5 < 6)) ->
> 
> (test cases are seldom reasonable). It worked then. Has the compiler
> been changed since then?
> 
> >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)))).
> >
> >Sigh.
> >
> >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.
> >
> I quite honestly don't really see the problem with the
> precedences. Whatever is wrong with your macro it isn't the
> precedences. How do you envisage that (size(X) == 2) be false? What
> should size of something usizable return?
> 
> Since and/or behave as "normal" operators it was thought better to add
> new constructions with explicit left-to-right semantics rather than
> modify and/or. After a while you get into a horrible mess if you start
> special casing certain functions (operators are functions).
> 
> Robert

-- 

/ Raimo Niskanen, Erlang/OTP, Ericsson AB



More information about the erlang-questions mailing list