[comp.lang.eiffel] a < b < c

sommar@enea.se (Erland Sommarskog) (08/15/89)

There is currently a discussion going on in comp.lang.misc
under the subject "What I like to see in an if-statement",
and the subject line I have chosen shows the desired feature.

In short the rule for a relational expression should be something
like:
    Rel_exp ::= Expression (Rel_op Expression)*
where ()* means one or more occurences. The semantic interpretation
would be than of a logical AND so that:
     a < b <= c > a + 2
would be a shorthand for
     a < b AND b <= c AND c > a + 2
When I took a compiler course ages ago, the little language I defined
had this feature. And there are several occasions when this would
relational expressions shorter and thus easier to read since what
is omitted is superflouos syntactic noise.
  I mentioned this in an article, and one reponse agreed with me,
and answered my question why so few language had it with the simple
"Algol didn't have it". And it sounds likely. When you sit down and
design a new language, things like boolean expressions is just
something you "take off the shelf". Anyway, since Eiffel still is
open for the changes for some more time, why not take the chance
and add it? Not an essential thing, but one of those little things
that makes life easier. Or is there some problem I have over-looked?
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se
"Hey poor, you don't have to be Jesus!" - Front 242

bertrand@eiffel.UUCP (Bertrand Meyer) (08/28/89)

From article <182@enea.se>, sommar@enea.se (Erland Sommarskog):
  
> [...] The rule for a relational expression should be something like:
>     Rel_exp ::= Expression (Rel_op Expression)*
> [...] The semantic interpretation would be than of a logical AND so that:
>      a < b <= c > a + 2
> would be a shorthand for
>      a < b AND b <= c AND c > a + 2
> [...] Since Eiffel still is open for changes for some more time,
> why not take the chance and add it? Not an essential thing,
> but one of those little things that makes life easier. Or
> is there some problem I have overlooked?

	I have tried to find an argument for not following
Mr. Sommarskog's suggestion and I cannot think of one.
As a matter of fact, many assertions in the basic Data Structure
Library and elsewhere would be written more simply in this way.

	It may be that the reason why no mainstream language has included the
form suggested by Mr. Sommarskog is that people feared ambiguity.
But the simple semantics he suggests (``and'') makes any such fear
unfounded.

	At first (and second) sight this seems to be the kind of extension
that only has advantages. It should find its way into version 3.

-- Bertrand Meyer
bertrand@eiffel.com

sommar@enea.se (Erland Sommarskog) (08/30/89)

Bertrand Meyer (bertrand@eiffel.UUCP) writes:
>	It may be that the reason why no mainstream language has included the
>form suggested by Mr. Sommarskog is that people feared ambiguity.

As I said in my first article it's more likely intertia as
correspondent said to me in mail.

>	At first (and second) sight this seems to be the kind of extension
>that only has advantages. It should find its way into version 3.

I'm pleased to hear to contributed to Eiffel's development. There
is one more detail to think of though:

     a < b < f()

Should the language guarantee that f is called? Or should the compiler
be allowed to skip the call if a >= b? My view is the latter, and a
quick glance in OOSC doesn't say that Eiffel has a differnt philosophy.
As the Ada LRM would say: a program that relies on a expression being
computed in any particular order is erroneous.
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se
The law of gravity should be forbidden execpt in downhills.

marku@cheops.eecs.unsw.oz (Mark Utting) (08/31/89)

From article <192@eiffel.UUCP>, by bertrand@eiffel.UUCP (Bertrand Meyer):
> From article <182@enea.se>, sommar@enea.se (Erland Sommarskog):
>   
>> [...] The rule for a relational expression should be something like:
>>     Rel_exp ::= Expression (Rel_op Expression)*
>> [...] The semantic interpretation would be than of a logical AND so that:
>>      a < b <= c > a + 2
>> would be a shorthand for
>>      a < b AND b <= c AND c > a + 2
> ........
> 
> 	At first (and second) sight this seems to be the kind of extension
> that only has advantages. It should find its way into version 3.
>
> -- Bertrand Meyer

I like this abbreviated notation, with one slight reservation.

"a < b <= c" is fine, but "d < e > f" seems to me to be less readable
than using an explicit `and'.  I agree that it is not ambiguous given
the above semantics, but it makes me wonder what the relationship between
"d" and "f" is.

When the relational operators all go in the same direction (possibly mixed
with equalities), the transitive relationships all hold as well.
Eg. "a" is clearly less than "c" in the above.
However, when increasing and decreasing operators are mixed, this nice
transitive property disappears.

I guess I would like to be able to abbreviate sequences of {<,<=,=}
operators, and sequences of {>,>=,=} operators, but not mix the two.

The specification language Z allows any boolean relational operators
to be abbreviated in this way, but published specifications seem to
keep to the convention mentioned above.


Mark Utting, Dept.Comp.Sci, UNSW, PO Box 1, Kensington, NSW, Australia 2033
   //		ACSnet,CSNET:	marku@cheops.unsw.oz
  //		BITNET/ARPA:	marku%cheops.unsw.oz@uunet.uu.net
\//		UUCP:		...!uunet!munnari!cheops.unsw.oz!marku

db@lfcs.ed.ac.uk (Dave Berry) (08/31/89)

In article <239@enea.se> sommar@enea.se (Erland Sommarskog) writes:
>I'm pleased to hear to contributed to Eiffel's development. There
>is one more detail to think of though:
>
>     a < b < f()
>
>Should the language guarantee that f is called? Or should the compiler
>be allowed to skip the call if a >= b?

Should the arguments be evaluated left-to-right, right-to-left, or
in arbitrary order?

Should the argument be evaluated exactly once, at most once, or any
number of times?

If the value of the expression is known before all the arguments are
evaluated, must the remaining arguments be evaluated, must they not be
evaluated, or is it up to the compiler?


The only strong feeling I have about these issues is that an argument
should not be evaluated more than once.  I.e.

	a < f() < b

should not be equivalent to

	a < f() and f() < b

but to

	tmp1 := a		-- if evaluation is left-to-right
	tmp2 := f()
	tmp1 < tmp2 and tmp2 < b

Dave Berry, Laboratory for Foundations      db%lfcs.ed.ac.uk@nsfnet-relay.ac.uk
    of Computer Science, Edinburgh Uni.	    <Atlantic Ocean>!mcvax!ukc!lfcs!db

   "Another hope, another dream, another truth, installed by the machine."

afscian@violet.waterloo.edu (Anthony Scian) (08/31/89)

In article <239@enea.se> sommar@enea.se (Erland Sommarskog) writes:
>I'm pleased to hear to contributed to Eiffel's development. There
>is one more detail to think of though:
>
>     a < b < f()
>
>Should the language guarantee that f is called? Or should the compiler
>be allowed to skip the call if a >= b? My view is the latter, and a
>quick glance in OOSC doesn't say that Eiffel has a differnt philosophy.
The expression a < b < c could expand into:

	a < b AND IF b < c
rather than
	a < b AND b < c

for boolean expressions in code and for assertions:

	a < b ; b < c

This would be the most useful expansions for the construct.

Anthony
//// Anthony Scian afscian@violet.uwaterloo.ca afscian@violet.waterloo.edu ////
"I can't believe the news today, I can't close my eyes and make it go away" -U2

ankle@ics.uci.edu (Rod Shankle) (09/01/89)

> should a < b < f () be allowed and if a >= b should the function be 
> called or not ??

Well, since f () is a function and functions shouldn't have any side
effects (refer to OOSC for a lot of examples and reasons why they shouldn't)
it doesn't matter (unless your profiling the program) if f () gets called
or not.
With that restriction even an expression such as a < f () < c should be
allowed.
BTW, most compilers evaluate IF a < b AND b < c THEN as
	IF a >= b THEN FALSE ELSE b < c

---	SHML	---

bbadger@x102c.harris-atd.com (Badger BA 64810) (09/03/89)

In article <1300@cheops.eecs.unsw.oz> marku@cheops.eecs.unsw.oz (Mark Utting) writes:
[...]
>
>I like this abbreviated notation, with one slight reservation.
>
>"a < b <= c" is fine, but "d < e > f" seems to me to be less readable
>than using an explicit `and'.  I agree that it is not ambiguous given
>the above semantics, but it makes me wonder what the relationship between
>"d" and "f" is.
>
>When the relational operators all go in the same direction (possibly mixed
>with equalities), the transitive relationships all hold as well.
                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>Eg. "a" is clearly less than "c" in the above.
>However, when increasing and decreasing operators are mixed, this nice
>transitive property disappears.
>
>I guess I would like to be able to abbreviate sequences of {<,<=,=}
>operators, and sequences of {>,>=,=} operators, but not mix the two.
>
>The specification language Z allows any boolean relational operators
>to be abbreviated in this way, but published specifications seem to
>keep to the convention mentioned above.
>
Please excuse my ignorance of Eiffel syntax.  I don't know the
syntax of Eiffel, but I've been following this discussion with interest.
(Perhaps someone could post an abbreviated Eiffel syntax, to give us
some of the flavor?)  

Also, in what follows, I'm assuming that relational operators can be
defined on user-defined data types.  If this isn't so, I'm sorry.

Holding to a single ``flow'' might seem to avoid ``syntax shock'', but
not all boolean operations on objects yeild transitive relations.
That is,``a < b and b < c'' does not imply ``a < c''.  My favorite
example of this is a probability function which compares the outcome
of dice.
I'll use C syntax (sorry):
Given:

typedef int die_t [6];
  die_t  a = {3,3, 3,3, 3,3};
  die_t  b = {2,2, 2,2, 6,6};
  die_t  c = {1,1, 4,4, 4,4};
int win_loss ( die_t p, die_t q) {
	int i,j;
	int win_loss;
	count = 0;
	for (i = 0; i < 6; i++) { for (j = 0; j < 6; j++) {
		if ( p[i] > q[j] ) count ++;
		if ( p[i] < q[j] ) count --;
	}}
}
int wins ( die_t p, die_t q) {	return win_loss(p,q) > 0;}
int loses ( die_t p, die_t q) {	return win_loss(p,q) < 0;}

Now it turns out that:
	     win_loss   loses           Relation (`a<b' is `loses(a,b)')
              --        -----    
	a b   12        True    	a < b
	b c    4        True     	b < c
	a c  -12	FALSE!   not  ( c < a )

Also keep in mind that ``not (a<=b)'' does not necessarily imply ``a>b''.  
Even when (a<b)  <==> (b>a) .
For example,
 (not subset(a,b) and not eq(a,b)) does not imply (subset(b,a)).

In conclusion, I like the idea of a compact notation, but I think
you'll have to restrict the relational operators.  In Ada, for
example, the not-equals operator (``/='') is derived from the equals
operator and the pre-defined BOOLEAN ``not'' operation.  You cannot
define ``/='' independently of ``=''.  On the other hand, in Ada, 
``<='' is totally independent of ``<'' and ``=''.  The relational
operators are, I think, constrained to return a BOOLEAN type.  (It's
been a while, so I might be wrong on this.)

What constraints to relational operators should be applied?  
What about purity and simplicity?  Does common usage supersede simplicity?
    -----	-	-	-	-	-	-	-	----
Bernard A. Badger Jr.	407/984-6385          |``Get a LIFE!''  -- J.H. Conway
Harris GISD, Melbourne, FL  32902             |Buddy, can you paradigm?
Internet: bbadger%x102c@trantor.harris-atd.com|'s/./&&/g' Tom sed expansively.

diamond@csl.sony.co.jp (Norman Diamond) (09/04/89)

In article <1300@cheops.eecs.unsw.oz> marku@cheops.eecs.unsw.oz (Mark Utting) writes:

>I like this abbreviated notation, with one slight reservation.

>"a < b <= c" is fine, but "d < e > f" seems to me to be less readable
>than using an explicit `and'.  I agree that it is not ambiguous given
>the above semantics, but it makes me wonder what the relationship between
>"d" and "f" is.

If you find "d < e > f" confusing, then vote against it at your
employer's style meeting.  Or forbid your subordinates to do it.

>The specification language Z allows any boolean relational operators
>to be abbreviated in this way, but published specifications seem to
>keep to the convention mentioned above.

This seems rather suitable.  Keep the rules simple so they can be
understood.  Bad programmers will be able to write bad programs, but
not everyone will have to.

--
-- 
Norman Diamond, Sony Corporation (diamond@ws.sony.junet)
  The above opinions are inherited by your machine's init process (pid 1),
  after being disowned and orphaned.  However, if you see this at Waterloo or
  Anterior, then their administrators must have approved of these opinions.

potter@ultima.cs.uts.oz (John Potter) (11/25/89)

 From article <192@eiffel.UUCP>, by bertrand@eiffel.UUCP (Bertrand
                                                          Meyer):
  >From article <182@enea.se>, sommar@enea.se (Erland Sommarskog):
>   
> > [...] The rule for a relational expression should be something like:
> >     Rel_exp ::= Expression (Rel_op Expression)*
> > [...] The semantic interpretation would be than of a logical AND so
> that:
> >      a < b <= c > a + 2
> > would be a shorthand for
> >      a < b AND b <= c AND c > a + 2
> > [...] Since Eiffel still is open for changes for some more time,
> > why not take the chance and add it? Not an essential thing,
> > but one of those little things that makes life easier. Or
> > is there some problem I have overlooked?
> 
>       I have tried to find an argument for not following
>       Mr. Sommarskog's suggestion and I cannot think of one.
>       As a matter of fact, many assertions in the basic Data Structure
>       Library and elsewhere would be written more simply in this way.
> 
>       It may be that the reason why no mainstream language has
>       included the form suggested by Mr. Sommarskog is that people feared
>       ambiguity.
>       But the simple semantics he suggests (``and'') makes any such fear
>       unfounded.

I've just got around to reading these articles and their followups.

It may be of passing interest to note that the language Miranda allows
precisely this form of relational expression. Miranda is a functional
language with non-strict semantics (i.e. uses lazy evaluation).
The semantic interpretation of
        a < b <= c > a + 2
would be akin to the Eiffel form
        a < b and then b <= c and then c > a + 2
The "then" corresponds to the non-strict semantics in Miranda.

I don't wish to debate whether Miranda is a mainstream language or not,
but it is attracting considerable interest as a vehicle for introductory
programming courses (more or less in competition with Scheme).

In our first year courses in Computer Science here at the University of
Technology, Sydney, we are currently introducing our students to both
Miranda and Eiffel. Miranda is taught as part of a Discrete Mathematics
subject, and Eiffel within our programming subjects.

yost@esquire.UUCP (David A. Yost) (11/27/89)

In article <16655@ultima.cs.uts.oz> potter@ultima.cs.uts.oz (John Potter) writes:
>
> From article <192@eiffel.UUCP>, by bertrand@eiffel.UUCP (Bertrand
>                                                          Meyer):
>  >From article <182@enea.se>, sommar@enea.se (Erland Sommarskog):
>>   
>> > [...] The rule for a relational expression should be something like:
>> >     Rel_exp ::= Expression (Rel_op Expression)*
>> > [...] The semantic interpretation would be than of a logical AND so
>> that:
>> >      a < b <= c > a + 2
>> > would be a shorthand for
>> >      a < b AND b <= c AND c > a + 2
>> > [...] Since Eiffel still is open for changes for some more time,
>> > why not take the chance and add it? Not an essential thing,
>> > but one of those little things that makes life easier. Or
>> > is there some problem I have overlooked?
>> 
>>       I have tried to find an argument for not following
>>       Mr. Sommarskog's suggestion and I cannot think of one.
>>       As a matter of fact, many assertions in the basic Data Structure
>>       Library and elsewhere would be written more simply in this way.
>> 
>>       It may be that the reason why no mainstream language has
>>       included the form suggested by Mr. Sommarskog is that people feared
>>       ambiguity.
>>       But the simple semantics he suggests (``and'') makes any such fear
>>       unfounded.
>
>I've just got around to reading these articles and their followups.
>
>It may be of passing interest to note that the language Miranda allows
>precisely this form of relational expression. Miranda is a functional
>language with non-strict semantics (i.e. uses lazy evaluation).
>The semantic interpretation of
>        a < b <= c > a + 2
>would be akin to the Eiffel form
>        a < b and then b <= c and then c > a + 2
>The "then" corresponds to the non-strict semantics in Miranda.

OK, I guess it's time someone said that the
Icon programming language (available free
from icon-project@arizona.edu, but please
give them a few bucks) can do this, plus Icon
expressions yield more information.  In most
languages you could divide the world of
expression values into two types: boolean
(used for control structures) and non-
boolean.  In Icon, by contrast, every
expression acts as both.  Every expression
either "succeeds" or "fails", giving you your
true/false indication, if you want to use it,
and, if the expression succeeds, it has a
(non-boolean) value, if you want to use it.
When any subexpression fails, expression
evaluation stops, and the entire expression
fails.  And everything is an expression in
Icon; there are no statements.

If a relational expression succeeds, it takes
the value of the right side.  So, the
expression

	(a < b) + 1 < c

evaluates like this

	 a   b   c   expression
	--- --- --- -----------------
	 2   1   3   no value - fails because a < b fails
	 1   2   3   no value - fails because b + 1 < c fails
	 1   2   4   c

This succeed/fail property of Icon
expressions is nice to use in practice.
Yet there is more still: if an expression
succeeds, it can be resumed, at which point
it can yield another value or fail.  Thus,
you will see many forms of multi-valued
"generator" expressions.  You can use each
value in turn or just the first value, if you
like.  For instance, the expression

	1 to 3

which yields 1, then 2, then 3, ... then
fails.  There are various control structures
that make it easy to take advantage of the
multiple values that expressions can
generate, such as

	every expression [ do expression ]

	while expression [ do expression ]

For example,

	every x := 1 to 3 do write (x)

Of course, Icon subroutines either succeed
or fail, and can be written to generate
additional values when resumed.

Icon is neat.  My ideal language would be
an Icon-ish Eiffel, that is, for example,
everything a succeed/fail multi-valued
expression instead of some things
statements and some things expressions,
{} syntax instead of keywords, semicolons
optional, and icon-like lists in the
library.

 --dave yost

budd@mist.cs.orst.edu (Tim Budd) (11/28/89)

I'm developing a new programming language called LEDA, which is designed to
be ``multiparadigm''.  That is, you can program in a logical (prolog
style), functional, object oriented or imparative style - or in any mix.
It provides generators similar (and largely taken from) Icon, as well as
many other features.

Several papers on LEDA are in various pipelines, but none has seen daylight
yet.  If you want to see various technical reports let me know and I can
send them.
--tim budd  (budd@cs.orst.edu)

peter@ficc.uu.net (Peter da Silva) (11/29/89)

I would like to note that this syntax has been used before. I implemented a
real-time control language that did this about 6 or 7 years ago. It's very
easy to implement, and the ambiguity does not produce much difficulty in
practice. I was skeptical at first, but now I'm a convert.

Too bad that project ended up getting canned due to overengineering. :-<
-- 
`-_-' Peter da Silva <peter@ficc.uu.net> <peter@sugar.lonestar.org>.
 'U`  --------------  +1 713 274 5180.
"The basic notion underlying USENET is the flame."
	-- Chuq Von Rospach, chuq@Apple.COM