[comp.lang.misc] What I'd really like to see in an if-statement...

tneff@bfmny0.UUCP (Tom Neff) (08/09/89)

The obvious drawback to defining 'triadc' as a macro

	#define triadc(a,o1,b,o2,c) ((a o1 b) && (b o2 c))

is side effects, e.g.

	if (triadc(' ', *cp++, '_'))
		do_the(wrong, thing);	/*  :-)  */
-- 
"We walked on the moon --	((	Tom Neff
	you be polite"		 )) 	tneff@bfmny0.UU.NET

karl@haddock.ima.isc.com (Karl Heuer) (08/10/89)

In article <8577@batcomputer.tn.cornell.edu> lacey@tcgould.tn.cornell.edu (John Lacey) writes:
>As I think we have all agreed that C is not the place for these extended
>constructs, I have directed follow-ups to comp.lang.misc.

I agree; sorry I didn't redirect it myself.  (c.l.m readers: the topic is the
hypothetical change to C to make "x < y < z" mean what a mathematician would
expect, rather than the useless interpretation that C currently attaches to
it, viz. "x<y && 1<z  ||  x>=y && 0<z".)

>I agree that it doesn't belong in C.  However, I also happen to think that
>Icon's semantics are horrible.  The idea that (a < b) either fails to produce
>a result or evaluates to b is completely unintuitive.

Well, the only time you care that it happens to evaluate to b is when you're
writing "a < b < c"; otherwise, you just use it in a boolean context, where
the only important part is whether it's true or false (i.e. does or doesn't
return a value).  The actual value doesn't matter.  I don't see that this is
any more of a problem than the fact that most implementations of isalpha()
return a random nonzero value (not necessarily 1) for success.

>[karl@haddock.ima.isc.com (Karl Heuer) writes:]
>>I doubt that the parse is any more difficult than the dangling-else problem.
>
>The parse would be more difficult.  The problems aren't analogous.  The 
>dangling-else problem is one of ambiguity.  Parsing a general relational
>expression is difficult because the same string will be used for multiple
>tokens.  For example, in (a < x < b), x has to be associated separately
>to its left and right.

I don't see what you're getting at.  You simply add a new production rule
which parses "a < x < b" as a ternary operator, and produce code equivalent to
	evaluate x into temp
	compare a with temp
	jump-if-ge FALSE-BRANCH
	compare temp with b
	jump-if-ge FALSE-BRANCH
Generating the temporary is trivial for a compiler; it's not as if this had to
be parsed by a macro preprocessor.

The lookahead to distinguish the constructs "E < E < E" and "E < E" is, I
believe, no worse than the problem of distinguishing "if (E) S;" and
"if (E) S; else S;".

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

preston@titan.rice.edu (Preston Briggs) (08/11/89)

In article <14251@haddock.ima.isc.com> 
>	karl@haddock.ima.isc.com (Karl Heuer) writes:
>	...	 You simply add a new production rule
>which parses "a < x < b" as a ternary operator, 
>and produce code equivalent to
>	evaluate x into temp
>	compare a with temp
>	jump-if-ge FALSE-BRANCH
>	compare temp with b
>	jump-if-ge FALSE-BRANCH
>Generating the temporary is trivial for a compiler; 
>it's not as if this had to
>be parsed by a macro preprocessor.
>
>The lookahead to distinguish the constructs "E < E < E" and "E < E" is, I
>believe, no worse than the problem of distinguishing "if (E) S;" and
>"if (E) S; else S;".

But you wouldn't want a single production to get a<b<c as a ternary operator;
you really want to be able to handle a < b < c < ... < n

And do you want it restricted to conditionals, or extended
to all expressions/statements?

This should all be easy; but I don't like it.  It feels "unnatural."
I think the problem is that you want to make relational operators
into a sort of control flow thing -- not really operators at all.
Compare + with your version of <.

	a+b+c     means           (a + b) + c
but
	a<b<c    doesn't mean     (a < b) < c
			   or      a < (b < c)


So, I guess it's a doable idea; it's just going to feel
really unnatural to a lot of people.  I prefer Pascal's
version, where it is illegal to write a<b<c at all.
This avoids any misinterpretation.  On the other hand,
I'd prefer a few more levels of precedence allowing me
to write
	a<b and b<c
instead of
	(a<b) and (b<c)

On the other hand, versions of LISP allow things like
	(+ a b c d)
and
	(< a b c d)

which seems best of all.  Maybe we should just give up on
"normal" algebraic notation as a bad idea extended too far.

Regards,
Preston Briggs
preston@titan.rice.edu

lacey@batcomputer.tn.cornell.edu (John Lacey) (08/11/89)

In article <516@brazos.Rice.edu>  (3383 of comp.lang.misc)
    preston@titan.rice.edu (Preston Briggs) writes:
}
} And do you want it restricted to conditionals, or extended
} to all expressions/statements?

It would be a relational expression, of course, just like "a < b".

} This should all be easy; but I don't like it.  It feels "unnatural."
} I think the problem is that you want to make relational operators
} into a sort of control flow thing -- not really operators at all.
} Compare + with your version of <.
} 
} 	a+b+c     means           (a + b) + c
} but
} 	a<b<c    doesn't mean     (a < b) < c
} 			   or      a < (b < c)

Just because the expression doesn't commute or associate doesn't mean
it is not a valid relation.  It certainly is not "a sort of control flow
thing".

} So, I guess it's a doable idea; it's just going to feel
} really unnatural to a lot of people.  I prefer Pascal's
} version, where it is illegal to write a<b<c at all.
} This avoids any misinterpretation.  

So far so good (not that I agree with you, but it is your preference).

} On the other hand, versions of LISP allow things like
} 	(+ a b c d)
} and
} 	(< a b c d)
} 
} which seems best of all.  Maybe we should just give up on
} "normal" algebraic notation as a bad idea extended too far.

One is postfix and the other is infix, but they have identical meanings.
So why is one unnatural and the other best of all?  Also, perhaps there
are places where algebraic notation [which, by the way, (< a b c d) is
an example of] is not the best option, but I don't think that programming
languages are such a place.  Indeed, algebra is only recently becoming
the powerful tool in programming that it is in mathematics (abstract data
types, algebraic specification, and so on).

} Preston Briggs
} preston@titan.rice.edu


-- 
John Lacey     lacey@tcgould.tn.cornell.edu    cornell!batcomputer!lacey

After August 16:  jjlacey@owucomcn.bitnet
If you have to, try  mdl@sppy00.UUCP or maybe {...}!osu-cis!sppy00!mdl

preston@titan.rice.edu (Preston Briggs) (08/11/89)

In article <8606@batcomputer.tn.cornell.edu> lacey@tcgould.tn.cornell.edu (John Lacey) writes:
>In article <516@brazos.Rice.edu>  (3383 of comp.lang.misc)
>    preston@titan.rice.edu (Preston Briggs) writes:
>} On the other hand, versions of LISP allow things like
>} 	(+ a b c d)
>} and
>} 	(< a b c d)
>} 
>} which seems best of all.  Maybe we should just give up on
>} "normal" algebraic notation as a bad idea extended too far.
>
>One is postfix and the other is infix, but they have identical meanings.
>So why is one unnatural and the other best of all?  Also, perhaps there
>are places where algebraic notation [which, by the way, (< a b c d) is
>an example of] is not the best option, but I don't think that programming
>languages are such a place.  Indeed, algebra is only recently becoming
>the powerful tool in programming that it is in mathematics (abstract data
>types, algebraic specification, and so on).

Yes, you're certainly correct about my mistakes.

On the other hand, the point I was attempting to make
still seems valid.  That is, explicitely parenthesized prefix
notation seems a better representation for complex expressions.
I will agree that simple expressions are more simply written
in C or Pascal---infix notation and commonly understood rules
of precedence help achieve a clear, compact representation.

But C has 16 levels of precedence!
I think this is an indication of too much complexity
crammed into the notion of <expression>.

I think Lisp/Scheme/... have the right idea,
at least regarding expressions---a simple, consistant
notation that can be easily extended.

Preston Briggs
preston@titan.rice.edu

preston@titan.rice.edu (Preston Briggs) (08/11/89)

In article <8606@batcomputer.tn.cornell.edu> 
   lacey@tcgould.tn.cornell.edu (John Lacey) writes:
>In article <516@brazos.Rice.edu>  (3383 of comp.lang.misc)
>    preston@titan.rice.edu (Preston Briggs) writes:
>} but
>} 	a<b<c    doesn't mean     (a < b) < c
>} 			   or      a < (b < c)
>
>Just because the expression doesn't commute or associate doesn't mean
>it is not a valid relation.

But if < doesn't associate, then it doesn't make sense to write a<b<c.

In C, < is left-associative.  You can write a<b<c (but the meaning
is perhaps suprising).

In Pascal, < doesn't associate.  You can't write a<b<c.

Preston Briggs
preston@titan.rice.edu

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

I think John Lacey (lacey@tcgould.tn.cornell.edu) said this:
>The parse would be more difficult.  The problems aren't analogous.  The
>dangling-else problem is one of ambiguity.  Parsing a general relational
>expression is difficult because the same string will be used for multiple
>tokens.  For example, in (a < x < b), x has to be associated separately
>to its left and right.

I have to object here. Way back at the university I took a compiler
course. In the tiny language I made for my assignment I defined the 
grammar relational expression something like:
   rel_exp ::= exp (rel_op exp)*
()* meaning 1 or more times easy. Trivial, isn't it? The semantic
interpretation was AND. I.e. 0 < x < 10 was interpreted as (0 < x)
AND (x < 10), which seems as the natural interpretation for the
case you would like to use it for. A thing like
    a = b <= z > y < b
wouldn't something to recommend but the langauge dealt with it the same
way.

Actually I have always been surprised that no language I have dealt
have had this feature since it is so easy to implement. Am I overlook-
ing something?
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se
"Hey poor, you don't have to be Jesus!" - Front 242

rrt@halley.UUCP (Robert Teisberg) (08/12/89)

In article <545@brazos.Rice.edu> preston@titan.rice.edu (Preston Briggs) writes:
>In Pascal, < doesn't associate.  You can't write a<b<c.

True, you usually can't, but associativity (or lack thereof) is not the
reason.  In Pascal, the expression parses as:

(a<b)<c

where (a<b) is an expression with a boolean value.  If c is also
boolean, this is a legitimate (though weird) expression.  If c is not
boolean, the compiler should complain of a type clash.

>Preston Briggs
>preston@titan.rice.edu


-- 
Bob Teisberg @ Tandem Computers, Inc. | ...!rutgers!cs.utexas.edu!halley!rrt
14231 Tandem Blvd.                    | soon to be rrt@mpd.tandem.com
Austin, Texas  78728                  | (512) 244-8119
Any resemblance to the opinions of a real person or corporation is concidental.

preston@titan.rice.edu (Preston Briggs) (08/12/89)

In article <561@halley.UUCP> rrt@halley.UUCP (Robert Teisberg) writes:
>In article <545@brazos.Rice.edu> preston@titan.rice.edu (Preston Briggs) writes:
>>In Pascal, < doesn't associate.  You can't write a<b<c.
>
>True, you usually can't, but associativity (or lack thereof) is not the
>reason.  In Pascal, the expression parses as:
>
>(a<b)<c
>
>where (a<b) is an expression with a boolean value.  If c is also
>boolean, this is a legitimate (though weird) expression.  If c is not
>boolean, the compiler should complain of a type clash.

Wait.  Check the BNF or railroad tracks.  (Pause while I try
to find a reference!)  In "Algorithms+Data Structures" (all I
can find right away), an Expression is defined:

	Expression ::= SimpleExpression [relation SimpleExpression]

where [x] denotes an optional "x".  So, an expression is a
SimpleExpression, optional followed by a Relation and another
SimpleExpression.  There can't be more than one relation.

Contrast this with the definition of SimpleExpression:

	SimpleExpression ::= [`+'|`-'] Term {AddOp Term}

where {x} denotes 0 or more x's.  Here we see an optional
leading + or -, followed by a Term, followed by a sequence
of AddOp's and Term's.

It's possible that some standard has changed this definition in the past
few years; I haven't kept up.  Try it on your favorite compiler!

	Preston

karl@haddock.ima.isc.com (Karl Heuer) (08/14/89)

In article <516@brazos.Rice.edu> preston@titan.rice.edu (Preston Briggs) writes:
>In article <14251@haddock.ima.isc.com> karl@haddock (Karl Heuer) writes:
>>which parses "a < x < b" as a ternary operator, 
>
>But you wouldn't want a single production to get a<b<c as a ternary operator;
>you really want to be able to handle a < b < c < ... < n

True; I was oversimplifying.  I'll cover the general case below.

>On the other hand, versions of LISP allow things like
>	(< a b c d)

That doesn't completely solve the problem; I want to be able to write
	0 <= i < N
without having to throw in +1/-1 on half of the expressions.  (I consider
a half-open interval to be the more natural endpoint-representation of a
range.)

Okay, then, here's one way to parse such constructs.  A comparison operator
like "a < b" returns an object of an internal type "cascadable boolean", whose
value is either {FALSE} or {TRUE, b}.  If a cascadable boolean is used in any
context other than the left operand of a compare, it immediately decays
into a normal boolean.  If it is the left operand of a compare, then
"{FALSE} < c" returns {FALSE} (but should probably still evaluate c for side
effects), while "{TRUE, b} < c" returns the same object as "b < c" (another
cascadable boolean).

This would apply to "==" and "!=" as well as "<" "<=" ">" ">=", and I would
make all six operators have the same precedence.  (The only reason for having
separate precedences for equality and relational operators is to allow
	a < b == c < d  /* do the two relations have the same truth-value? */
, which would still be legal if properly parenthesized -- enclosing a
cascadable boolean in parenthesis would also force the decay into a normal
boolean.)

(The above is an example of how to implement it, and perhaps how it would have
to be defined in the official language specs.  The language reference manual
can simply say that "expr relop expr relop ... relop expr" works the way a
mathematician might expect, and the whole construct returns a single boolean.)

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) (08/14/89)

I've been following this, wondering if someone form the Icon group
would speak up. Since nobody has, and Karl came close to their
solution, I'll put an oar in...

In article <14278@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes:
<Okay, then, here's one way to parse such constructs.  A comparison operator
<like "a < b" returns an object of an internal type "cascadable boolean", whose
<value is either {FALSE} or {TRUE, b}.  If a cascadable boolean is used in any
<context other than the left operand of a compare, it immediately decays
<into a normal boolean.  If it is the left operand of a compare, then
<"{FALSE} < c" returns {FALSE} (but should probably still evaluate c for side
<effects), while "{TRUE, b} < c" returns the same object as "b < c" (another
<cascadable boolean).

The Icon group find a slightly cleaner way to do this. Instead of
expression evalutaing to booleans, they either produce a value, or
"fail". Any expressions including a failed expression also fail, except
for "not" (which is classed as a control structure). If the expression
fed to not fails, then it returns a null value; otherwise, it fails.

Control constructs treat failed expressions as false, and valued
expressions as true. Relops are handled roughly as above, except that
where they return the value of the right-hand operand or fail. So that

	if a < b < c < d then

Will work as you'd expect - succeeding only if all the comparisons are
true. Likewise for:

	if a < b <= c = d < e then

etc, etc, etc.

I found this feature quite nice, and easy to work with. The concept of
"failure" also has interesting implications elsewhere, and works well
with the rest of the language.

The reference is "The Icon Programming Language", by Griswold &
Griswold. You can get Icon by ftp from several sites on the internet.

	<mike
--
Tell me how d'you get to be				Mike Meyer
As beautiful as that?					mwm@berkeley.edu
How did you get your mind				ucbvax!mwm
To tilt like your hat?					mwm@ucbjade.BITNET

peter@ficc.uu.net (Peter da Silva) (08/14/89)

In article <14278@haddock.ima.isc.com>, karl@haddock.ima.isc.com (Karl Heuer) writes:
> Okay, then, here's one way to parse such constructs.  [ complex explanation
  of run-time evaluation of !a < b <= c! using pairs of values ]

Well, that's one way of implementing the run-time code. Doesn't say anything
about parsing it, though. Parsing is easy... in yacc you'd do something like
this:

boolean		: expression
		| boolean relop expression
		;

In a recursive-descent parser:

	parse_relop()	/* Called on seeing a relation operator */
	{
		while(is_relop(next_token)) {
			shift();
			expression();
		}
	}

Code generation, now. You want to end up with something like this:

For the expression !a < b <= c!...

	evaluate A
	evaluate B
	cmp A,B
	bge FAIL
	evaluate C, with A possibly scratched.
	cmp B,C
	ble SUCCEED
FAIL:	action on failure (go to end of if stmt, push 0, whatever)
	...
SUCCEED:action on success (may be inside if stmt, push 1, whatever)

For a stupid stack machine compiler, putting it in the RD parser above:

	parse_relop()
	{
		LABEL fail = genlab();
		LABEL succeed = genlab();
		LABEL end = genlab();

		while(1) {
			TOKEN saved;
			
			saved = next_token;
			shift();

			expression();

			if(is_relop(next_token)) {
				gen(SAVE_TOP); /* copies top under second */
				gen_branch(reverse_sense(saved), fail);
				continue;
			} else {
				gen_branch(saved, succeed);
				break;
			}
		}
		gen_target(fail);
		gen_push(FALSE);
		gen_branch(always, end);
		gen_target(succeed);
		gen_push(TRUE);
		gen_target(end);
	}

You will note that there is considerable room for optimisation :->.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Business: peter@ficc.uu.net, +1 713 274 5180. | "The sentence I am now
Personal: peter@sugar.hackercorp.com.   `-_-' |  writing is the sentence
Quote: Have you hugged your wolf today?  'U`  |  you are now reading"

dave@PRC.Unisys.COM (David Lee Matuszek) (08/15/89)

In article <178@enea.se> sommar@enea.se (Erland Sommarskog) writes:
>I think John Lacey (lacey@tcgould.tn.cornell.edu) said this:
>>The parse would be more difficult.  The problems aren't analogous.  The
>>dangling-else problem is one of ambiguity.  Parsing a general relational
>>expression is difficult because the same string will be used for multiple
>>tokens.  For example, in (a < x < b), x has to be associated separately
>>to its left and right.
>
>I have to object here. Way back at the university I took a compiler
>course. In the tiny language I made for my assignment I defined the 
>grammar relational expression something like:
>   rel_exp ::= exp (rel_op exp)*
>()* meaning 1 or more times easy. Trivial, isn't it? The semantic
>interpretation was AND. I.e. 0 < x < 10 was interpreted as (0 < x)
>AND (x < 10), which seems as the natural interpretation for the
>case you would like to use it for. A thing like
>    a = b <= z > y < b
>wouldn't something to recommend but the langauge dealt with it the same
>way.
>
>Actually I have always been surprised that no language I have dealt
>have had this feature since it is so easy to implement. Am I overlook-
>ing something?
>-- 

Sorry for the long insertion, but context is important.

A couple of years ago I developed a small special-purpose language for
the project I was involved in.  One of the things I did was to
implement extended relational expressions such as described above.  I
wrote both an interpreter and a compiler for the language, and it got
a fair amount of use.  It wasn't hard.

I don't think you're overlooking anything.  I had no trouble at all
with that part of the language.  You do have to decide what to do
about expressions such as "x < (y < z)" ["illegal" is a good choice!].

I don't think it would be a good idea to try to extend C in this way,
since x < y has an interpretation that only a hacker could love (an
integer rather than a truth value), but Pascal-like languages are no
problem.  Like you, I don't know why more languages don't have this
perfectly natural construct.

BTW, I also implemented

        all <variable> in <set or list> satisfy <logical expression>
        each <variable> in <set or list> satisfies <logical expression>

        some <variable> in <set or list> satisfies <logical expression>

(The first two are just syntactic variants of each other.)  I also
meant to add the following, but never got around to it:

        no <variable> in <set or list> satisfies <logical expression>

The <variable> is used in the logical expression; if "all/each" or
"no" fails, or if "some" succeeds, the <variable> retains the (first)
value that caused this to happen, otherwise the <variable> is
undefined.  These aren't hard either, and save the programmer from
explicitly writing loops for some common cases.  I think these are not
common because Pascal-like languages do not generally have sets or
lists as supported data types.

-- Dave Matuszek (dave@prc.unisys.com)
-- Unisys Corp. / Paoli Research Center / PO Box 517 / Paoli PA  19301
-- Any resemblance between my opinions and those of my employer is improbable.
Remember, too, that 1989 is the 17th anniversary of the LAST man on the moon.

firth@sei.cmu.edu (Robert Firth) (08/15/89)

In article <178@enea.se> sommar@enea.se (Erland Sommarskog) writes:

[ allowing 'x<y<z' to mean 'x<y & y<z']

>Actually I have always been surprised that no language I have dealt
>have had this feature since it is so easy to implement. Am I overlook-
>ing something?

The above is a feature of the language BCPL.  In simple cases, it
works very well indeed:

	if 'A' <= ch <= 'Z' do ...

In complicated cases, it can trip you up:

	if x < f() < y do ...

might call f() once or twice, for reasons difficult to explain to a
beginner.  And beginners have this habit of trying complicated cases,
rather the way kittens like ravelling string.

lacey@batcomputer.tn.cornell.edu (John Lacey) (08/15/89)

In talking about _Real Conditionals_ :), 
In article <3829@bd.sei.cmu.edu> of comp.lang.misc
    firth@sei.cmu.edu (Robert Firth) writes:
} The above is a feature of the language BCPL.  In simple cases, it
} works very well indeed:
} 
} 	if 'A' <= ch <= 'Z' do ...
} 
} In complicated cases, it can trip you up:
} 
} 	if x < f() < y do ...
} 
} might call f() once or twice, for reasons difficult to explain to a
} beginner.  And beginners have this habit of trying complicated cases,
} rather the way kittens like ravelling string.

Then, the above is _not_ a feature of BCPL.  However, you weren't expected
to know that, unless you have been following this thread from comp.lang.c .

The original question (_way_ back) was a open switch statement that allowed
arbitrary expressions, and picked the path of one that is true (aka Dijkstra's
if-fi construct) and also *evaluated each expression only once*.  That last
is the key.  Then we moved to simply getting full blown conditionals, like
those in mathematics.  If (x < f() < y) ever has side effects problems in
math., I should change majors or something, 'cause it's time to get out. :-)

So far, Lisp, Icon, and BCPL have all tried and failed to meet the challenge
(Icon came PDClose). Any more takers?

-- 
John Lacey     lacey@tcgould.tn.cornell.edu    cornell!batcomputer!lacey

After August 16:  jjlacey@owucomcn.bitnet
If you have to, try  mdl@sppy00.UUCP or maybe {...}!osu-cis!sppy00!mdl

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

In article <1989Aug14.022903.22953@agate.berkeley.edu> mwm@eris.berkeley.edu (Mike Meyer) writes:
>
>The Icon group find a slightly cleaner way to do this. Instead of
>expression evalutaing to booleans, they either produce a value, or
>"fail". Any expressions including a failed expression also fail, except
>for "not" (which is classed as a control structure).
>
>Likewise for:
>
>	if a < b <= c = d < e then


What about  (a < b) = (d < e), i.e. comparing results of relational
operations?  Presumably this is equivalent to

	if a < b and d < e then b = e [else fail]

and not to the expected result from boolean logic.  Or does bracketing
a relational expression force it to produce a canonical truth value (ugh) ?

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

      Rhetoric 101: Use of "scare" quotes and the phrase "so-called".

peter@ficc.uu.net (Peter da Silva) (08/15/89)

In article <3829@bd.sei.cmu.edu>, firth@sei.cmu.edu (Robert Firth) writes:
> The above is a feature of the language BCPL...

> 	if x < f() < y do ...

> might call f() once or twice, for reasons difficult to explain to a
> beginner.

Every now and then I read about something that gives me the same
sensation as discovering a hole in a baby-wipe when changing a soiled
daiper. If the language is designed so that f() can be called twice,
then that is a design flaw. Boy, I'm glad they didn't write UNIX at
Cambridge.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Business: peter@ficc.uu.net, +1 713 274 5180. | "The sentence I am now
Personal: peter@sugar.hackercorp.com.   `-_-' |  writing is the sentence
Quote: Have you hugged your wolf today?  'U`  |  you are now reading"

peter@ficc.uu.net (Peter da Silva) (08/15/89)

In article <8620@batcomputer.tn.cornell.edu>, lacey@batcomputer.tn.cornell.edu (John Lacey) writes:
> So far, Lisp, Icon, and BCPL have all tried and failed to meet the challenge
> (Icon came PDClose). Any more takers?

The Hydril Smart RTU programming language.

	a < b < c

Evaluated TRUE if a < b && b < c, FALSE otherwise. No expression is
evaluated more than once. If a >= b, then c is not evaluated at all
(lazy evaluation). Any sequence of expressions followed by relational
operators were valid.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Business: peter@ficc.uu.net, +1 713 274 5180. | "The sentence I am now
Personal: peter@sugar.hackercorp.com.   `-_-' |  writing is the sentence
Quote: Have you hugged your wolf today?  'U`  |  you are now reading"

nevin1@cbnewsc.ATT.COM (nevin.j.liber) (08/16/89)

In article <178@enea.se> sommar@enea.se (Erland Sommarskog) writes:

>Actually I have always been surprised that no language I have dealt
>have had this feature since it is so easy to implement. Am I overlook-
>ing something?

There are a few things.  In evaluating the following expression:

	a < b < c < ... < n

where a,b,c,...,n are arbituary EXPRESSIONS which *may have side effects*
(something which mathematicians using this notation don't normally deal
with), these are some of the issues which arise:

Is the order of evaluation left to right, right to left, or arbituary?

If "a < b" is false, is c necessarily still evaluated?

Are a,b,c,...,n each evaluated only once, at most once, or as many
times as necessary?


The answers to these questions have a profound effect on the spirit of
the language, the style of code written in the language, the
implementation of the language, the possible optimisations for the
language, etc.  Different languages will have different answers
to these questions (as well as the question "Does this construct really
fit in with the rest of the language?").  Although at a first pass it
is easy to implement, the real question becomes "Will this construct be
truly beneficial to the language?"  Or, rephrasing this question
pessimistically, "Overall, will this construct be detrimental to the
language?"
-- 
 _ __	NEVIN ":-)" LIBER  nevin1@ihlpb.ATT.COM  (312) 979-4751  IH 4F-410
' )  )			 "We are almost into the '90s; *nothing* is wierd."
 /  / _ , __o  ____	   -- Buzz Kelman, Newsman & Bluesman, WLUP, 7/28/89
/  (_</_\/ <__/ / <_	As far as I know, these are NOT the opinions of AT&T.

nevin1@cbnewsc.ATT.COM (nevin.j.liber) (08/16/89)

In article <5689@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
|In article <3829@bd.sei.cmu.edu>, firth@sei.cmu.edu (Robert Firth) writes:

|> 	if x < f() < y do ...

|> might call f() once or twice, for reasons difficult to explain to a
|> beginner.

|If the language is designed so that f() can be called twice,
|then that is a design flaw.

But is f() even called once??  Suppose x=1 and y=0.  I do the x<y
comparison first.  Since I now know that the entire expression is false,
should I bother to evaluate f()?  I can see arguments both ways; either
decision will have a profound effect on the resulting language.
-- 
 _ __	NEVIN ":-)" LIBER  nevin1@ihlpb.ATT.COM  (312) 979-4751  IH 4F-410
' )  )			 "We are almost into the '90s; *nothing* is wierd."
 /  / _ , __o  ____	   -- Buzz Kelman, Newsman & Bluesman, WLUP, 7/28/89
/  (_</_\/ <__/ / <_	As far as I know, these are NOT the opinions of AT&T.

peter@ficc.uu.net (Peter da Silva) (08/16/89)

In article <2452@cbnewsc.ATT.COM>, nevin1@cbnewsc.ATT.COM (nevin.j.liber) writes:
> In article <5689@ficc.uu.net> peter@ficc.uu.net (Peter da Silva) writes:
> |In article <3829@bd.sei.cmu.edu>, firth@sei.cmu.edu (Robert Firth) writes:
   [ in BCPL ]
> |> 	if x < f() < y do ...

> |> might call f() once or twice, for reasons difficult to explain to a
> |> beginner.

> |If the language is designed so that f() can be called twice,
> |then that is a design flaw.

> But is f() even called once??

In this case, yes. If it's !x < y < f() < z!, then maybe not.

> Suppose x=1 and y=0.  I do the x<y
> comparison first.

Why? You don't know that the language specifies that this statement
makes any assumptions about x relative to y. I know BCPL doesn't, and
that's the language we're immediately referencing.

> I can see arguments both ways; either
> decision will have a profound effect on the resulting language.

Vice-versa, the language will have a profound effect on the decision.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.
Business: peter@ficc.uu.net, +1 713 274 5180. | "The sentence I am now
Personal: peter@sugar.hackercorp.com.   `-_-' |  writing is the sentence
Quote: Have you hugged your wolf today?  'U`  |  you are now reading"

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

David Lee Matuszek (dave@PRC.Unisys.COM) writes:
>I don't think you're overlooking anything.  I had no trouble at all
>with that part of the language.  You do have to decide what to do
>about expressions such as "x < (y < z)" ["illegal" is a good choice!].

In Pascal x < (y < z) is perfectly legal if x is boolean. As far
as over-looking, I can only think one thing and that is expressions
like a < b < f(). Should f always be called? Well, the easy answer
is that such a think is not defined by the language and any program
that relies on that f is always called (or only called when necessary)
is clearly erroneous.

>I think these are not
>common because Pascal-like languages do not generally have sets or
>lists as supported data types.

Almost true. Pacal itself has sets though.
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se
"Hey poor, you don't have to be Jesus!" - Front 242

gudeman@arizona.edu (David Gudeman) (08/18/89)

In article  <1989Aug14.022903.22953@agate.berkeley.edu> mwm@eris.berkeley.edu (Mike (I'll think of something yet) Meyer) writes:
[summary: in Icon, (1) a relational operator "fails" if the relation
does not hold, and produces the value of the right operand if the
relation holds.  (2) if one argument to an operation fails, the whole
operation fails.  (3) conditional contexts like "if <cond> then" and
"while <cond> do" use failure as false, and any value as "true".]
>
>	if a < b < c < d then
>
>Will work as you'd expect - succeeding only if all the comparisons are
>true. Likewise for:
>
>	if a < b <= c = d < e then

This mechanism has much more far-reaching consequences that just
allowing relational operators to "cascade" properly.  Here are a
couple of other Icon expressions:

i := (i < j)   # assign j to i only if i is less than j

# the | symbol returns the results of both operands, one at a time
if f(i) < (j | k) then ... # if result of f(i) is less than j or k then ...
-- 
					David Gudeman
Department of Computer Science
The University of Arizona        gudeman@arizona.edu
Tucson, AZ 85721                 {allegra,cmcl2,ihnp4,noao}!arizona!gudeman

gudeman@arizona.edu (David Gudeman) (08/20/89)

In article  <8620@batcomputer.tn.cornell.edu> lacey@batcomputer.tn.cornell.edu (John Lacey) writes:
>In talking about _Real Conditionals_ :), 
>...  Then we moved to simply getting full blown conditionals, like
>those in mathematics.  If (x < f() < y) ever has side effects problems in
>math., I should change majors or something, 'cause it's time to get out. :-)
>
>So far, Lisp, Icon, and BCPL have all tried and failed to meet the challenge
>(Icon came PDClose). Any more takers?

Urr.  I thought both Lisp and Icon succeeded.  They both evaluate each
argument exactly once and produce a conditional result that is true
exactly when the corresponding value in math is true.

Are you complaining about the fact that those languages don't use
boolean values?  (Lisp uses NIL/non-NIL and Icon uses
failure/success).  If so, I should point out that math doesn't use
boolean values as the result of (in)equalities either.  In math the
(in)equality is just an assertion that tells something about the
variables in the equation, but in functional/procedural programming
languages, (in)equalities are only used as controls for conditional
structures, and they work fine in both Lisp and Icon.

To be _really_ math-like the expression (i < j < k) should create a
condition on i, j, and k such the relation holds.  If this is
impossible due to other constraints, then the program should say that
there is a contradiction.  Icon actually comes closer to this than a
language with boolean results would.
-- 
					David Gudeman
Department of Computer Science
The University of Arizona        gudeman@arizona.edu
Tucson, AZ 85721                 {allegra,cmcl2,ihnp4,noao}!arizona!gudeman

gudeman@arizona.edu (David Gudeman) (08/22/89)

In article  <126@castle.ed.ac.uk> db@lfcs.ed.ac.uk (Dave Berry) writes:
>[in Icon]...
>What about  (a < b) = (d < e), i.e. comparing results of relational
>operations? ...
>and not to the expected result from boolean logic.  Or does bracketing
>a relational expression force it to produce a canonical truth value (ugh) ?

No.  Icon doesn't have anything resembling a boolean type.  I might
point out that the expression 

    (a < b) = (d < e)

is from _extremely_ obscure boolean logic, not from common high school
algebra.  No one would know what to do with it except digital
engineers, mathematicians and Pascal programmers.  Icon was written
for a larger audience.

And furthermore,

#include <soapbox.bool>

Boolean algebra is an inelegant hack in programming languages.
Programming languages should either restrict relations to conditional
contexts (ick) or find an interesting and useful purpose for
relationals outside of conditional contexts (like C, Lisp, and Icon
have done).  Actually, boolean algebra is an attempt at the second
option, but a failed one.  Why use a trivial domain like truth values
when it can easily be subsumed into a larger, more interesting domain?
-- 
					David Gudeman
Department of Computer Science
The University of Arizona        gudeman@arizona.edu
Tucson, AZ 85721                 {allegra,cmcl2,ihnp4,noao}!arizona!gudeman

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

In article <13359@megaron.arizona.edu> gudeman@arizona.edu (David Gudeman) writes:
>In article  <8620@batcomputer.tn.cornell.edu> lacey@batcomputer.tn.cornell.edu (John Lacey) writes:
>>In talking about _Real Conditionals_ :), 
>>So far, Lisp, Icon, and BCPL have all tried and failed to meet the challenge
>
>Urr.  I thought both Lisp and Icon succeeded.  They both evaluate each
>argument exactly once and produce a conditional result that is true
>exactly when the corresponding value in math is true.

I agree about Icon, but are you sure about Lisp?  I thought that
(< a b) returned either t or nil.  If so, although it can handle
cases like (< a b c d), it can't handle (<= (< a b) c).

Any functional language can write the equivalent of (< a b c d).

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."

gateley@m2.csc.ti.com (John Gateley) (09/01/89)

In article <282@castle.ed.ac.uk> db@lfcs.ed.ac.uk (Dave Berry) writes:
>In article <13359@megaron.arizona.edu> gudeman@arizona.edu (David Gudeman) writes:
>>In article  <8620@batcomputer.tn.cornell.edu> lacey@batcomputer.tn.cornell.edu (John Lacey) writes:
>>>In talking about _Real Conditionals_ :), 
>>>So far, Lisp, Icon, and BCPL have all tried and failed to meet the challenge
>>
>>Urr.  I thought both Lisp and Icon succeeded. [...]
>I agree about Icon, but are you sure about Lisp?  I thought that
>(< a b) returned either t or nil.  If so, although it can handle
>cases like (< a b c d), it can't handle (<= (< a b) c).

First, do
(setf (symbol-function '<=help) (symbol-function '<=))
for all the relational predicates.

Next define a macro:
(defmacro <= (&rest args)
  (let ((result (tree-walk args)))
    result))
and so on for all the relational predicates.

Here, treewalk is a function which basically restructures the input so that
nested relations are handled properly: for example (<= (< a b) c)
means (let ((b-temp b)) (and (< a b-temp) (<= b-temp c)).

Cautions: this may not work someday in CL, as I think the cleanup committee
decided that lisp: functions may not be redefined. Also, if it does work
it may cause a performance hit since the compiler might have special
knowledge about <= and friends.

So, Lisp succeeds. The macro facility in Lisp gives you the ability to
model just about any programming syntax you want (within the inherent
bounds of lisp syntax).

John
gateley@m2.csc.ti.com

kirshenb@hplabsb.HP.COM (Evan Kirshenbaum) (09/06/89)

In article <89723@ti-csl.csc.ti.com> gateley@m2.UUCP (John Gateley) writes:
>In article <282@castle.ed.ac.uk> db@lfcs.ed.ac.uk (Dave Berry) writes:
>>In article <13359@megaron.arizona.edu> gudeman@arizona.edu (David Gudeman) writes:
>>>In article  <8620@batcomputer.tn.cornell.edu> lacey@batcomputer.tn.cornell.edu (John Lacey) writes:
>>>>In talking about _Real Conditionals_ :), 
>>>>So far, Lisp, Icon, and BCPL have all tried and failed to meet the challenge
>>>
>>>Urr.  I thought both Lisp and Icon succeeded. [...]
>>I agree about Icon, but are you sure about Lisp?  I thought that
>>(< a b) returned either t or nil.  If so, although it can handle
>>cases like (< a b c d), it can't handle (<= (< a b) c).

In scheme, one should be able to do something of the form:

(extend-syntax (order)
  ((order) '#!true)
  ((order a op b more ...)
   (with ((temp (gensym)))
     (let ((temp b))
       (and (op a temp)
            (order temp more ...))))))

which would allow you to write infix relations of the form
   (order a < b >= c != d = e divides f)
This allows any binary operation to be used as an operator, and should
be trivially optimized by the compiler.

Evan Kirshenbaum
    HP Laboratories
    3500 Deer Creek Road, Building 26U
    Palo Alto, CA  94304

    kirshenbaum@hplabs.hp.com
    (415)857-7572
 

kirshenb@hplabsb.HP.COM (Evan Kirshenbaum) (09/06/89)

In article <5410@hplabsb.HP.COM> kirshenb@hplabsb.UUCP (Evan Kirshenbaum) makes a boo-boo:
>In scheme, one should be able to do something of the form:
>
>(extend-syntax (order)
>  ((order) '#!true)

 should be:  ((order a) '#!true)

>  ((order a op b more ...)
>   (with ((temp (gensym)))
>     (let ((temp b))
>       (and (op a temp)
>            (order temp more ...))))))
>
Evan Kirshenbaum
    HP Laboratories
    3500 Deer Creek Road, Building 26U
    Palo Alto, CA  94304

    kirshenbaum@hplabs.hp.com
    (415)857-7572