# principle of least surprise

14 messages
Open this post in threaded view
|

## principle of least surprise

 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). 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. /martin
Open this post in threaded view
|

## principle of least surprise

 But, surprise: -define(is_foo(X), is_atom(X) ; is_tuple(X), (size(X) == 2)). /Magnus 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). > >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. > > > >/martin >   >
Open this post in threaded view
|

## principle of least surprise

 Magnus Fr?berg wrote: > But, surprise: > > -define(is_foo(X), is_atom(X) ; is_tuple(X), (size(X) == 2)). Right, but then you can't use is_foo as other booleans, e.g.     IsBar = (?is_foo(X) or is_list(X)), or whatever. /martin > > /Magnus > > 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). > > > >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. > > > > > > > >/martin > >   > > >
Open this post in threaded view
|

## principle of least surprise

 In reply to this post by Martin Bjorklund-2 I guess your radical suggestions to change precedence for 'and' and 'or', or to remove 'orelse' and also 'andalso' are out of the question, for backwards compatibility reasons. What about allowing 'orelse' and also 'andalso' in guards? That will probably happen one day. mbj (Martin Bjorklund) writes: > 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). > > 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. > > > > /martin -- / Raimo Niskanen, Erlang/OTP, Ericsson AB
Open this post in threaded view
|

## principle of least surprise

 Raimo Niskanen wrote: > I guess your radical suggestions to change precedence for > 'and' and 'or', or to remove 'orelse' and also 'andalso' > are out of the question, for backwards compatibility > reasons. Do you really think that changing precedence for and/or will break old code? As for andalso and orelse, I realize that it probably won't happen, but if it did, is it really such a big thing?  A large project would bring in the new erlang and recompile, and then the compiler would complain.  It's trivial to change the code (if precedence for or/and is changed).  Or maybe you could use some flag to the compiler which could be used for old code? > What about allowing 'orelse' and also 'andalso' in guards? > That will probably happen one day. Better than nothing of course, but wouldn't it be great to fix this mis-feature and make the language better? /martin
Open this post in threaded view
|

## principle of least surprise

 mbj wrote: > As for andalso and orelse, I realize that it probably won't happen, > but if it did, is it really such a big thing?  A large project would > bring in the new erlang and recompile, and then the compiler would > complain.  It's trivial to change the code (if precedence for or/and > is changed). I meant 'if evaluation rules for and/or are changed'.  or something. /martin
Open this post in threaded view
|

## principle of least surprise

 In reply to this post by Martin Bjorklund-2 >Better than nothing of course, but wouldn't it be great to fix this >mis-feature and make the language better? >   > Hm, what, in your opinion, about the possibility to be an arbitrary function (returning true or false, of course) in guards? Will it make the language better? Best regards, Linker Nick.
Open this post in threaded view
|

## principle of least surprise

 Nick Linker wrote: > > >Better than nothing of course, but wouldn't it be great to fix this > >mis-feature and make the language better? > >   > > > Hm, what, in your opinion, about the possibility to be an arbitrary > function (returning true or false, of course) in guards? Will it make > the language better? Maybe I should have added "and more consistent".  Anyway I think arbitrary functions in guards is an orthogonal question.  Personally I think it would be nice but it's not that big deal. /martin
Open this post in threaded view
|

## principle of least surprise

 --- mbj wrote: > Nick Linker wrote: > > > > >Better than nothing of course, but wouldn't it be > great to fix this > > >mis-feature and make the language better? > > >   > > > > > Hm, what, in your opinion, about the possibility > to be an arbitrary > > function (returning true or false, of course) in > guards? Will it make > > the language better? > > Maybe I should have added "and more consistent". > Anyway I think > arbitrary functions in guards is an orthogonal > question.  Personally I > think it would be nice but it's not that big deal. Well, you seem to want to introduce abstractions into your guards by way of macros (?is_foo), and also seem to want to use the same thing in expressions ... so actually permitting you to do that by means of the plain old function call (is_foo) doesn't seem like quite an orthogonal issue. I do agree that guards beyond the use of "," and ";" seem unsatisfactory at this point. (Basically, I think things would have turned out for the better if the designers had taken their inspiration from Prolog.) Nor do I really see the point of two collections of nearly-identical type test primitives (is_X/1 vs X/1). Best, Thomas                 __________________________________ Yahoo! FareChase: Search multiple travel sites in one click. http://farechase.yahoo.com
Open this post in threaded view
|

## principle of least surprise

 On 2005-11-22 15:25, Thomas Lindgren wrote: ...deleted > Nor do I really see the point of two collections of > nearly-identical type test primitives (is_X/1 vs X/1). the question is better stated as why adding is_X/1 when there already exists X/1? afaik the X/1 type test primitives where the only ones in the beginning.   is_X/1 where added afterward. backwards compatibility makes X/1 stay. bengt
Open this post in threaded view
|

## principle of least surprise

 In reply to this post by Martin Bjorklund-2 The problem here would be where you get code which goes through the compiler but is now semantically different because of the changed precedence. I can imagine how popular that would be! Robert mbj wrote: >Raimo Niskanen wrote: >   > >>I guess your radical suggestions to change precedence for >>'and' and 'or', or to remove 'orelse' and also 'andalso' >>are out of the question, for backwards compatibility >>reasons. >>     >> > >Do you really think that changing precedence for and/or will break old >code? > >As for andalso and orelse, I realize that it probably won't happen, >but if it did, is it really such a big thing?  A large project would >bring in the new erlang and recompile, and then the compiler would >complain.  It's trivial to change the code (if precedence for or/and >is changed).  Or maybe you could use some flag to the compiler which >could be used for old code? > >   > >>What about allowing 'orelse' and also 'andalso' in guards? >>That will probably happen one day. >>     >> > >Better than nothing of course, but wouldn't it be great to fix this >mis-feature and make the language better? > > >/martin > >   > -------------- next part -------------- An HTML attachment was scrubbed... URL:
Open this post in threaded view
|

## principle of least surprise

 In reply to this post by Martin Bjorklund-2 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