[comp.lang.misc] := versus ==

peter@ficc.ferranti.com (Peter da Silva) (07/31/90)

I think the best solution to this is to use ":=" for assignment and "==" for
equality. That way there would be no problem with using the wrong one in the
wrong context by accident.

(aside: the reason = versus == comes up in C has nothing to do with mathematics
 or ease of typing, but because assignment is an *operator*, not a *statement*.
 There do exist languages where = is used for both purposes with no possibility
 of confusion, and in fact the old Berkeley Pascal compiler (pi) would turn =
 in an assignment context into := in a completely reliable manner)
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
<peter@ficc.ferranti.com>

thornley@cs.umn.edu (David H. Thornley) (07/31/90)

In article <=L-4T-A@ggpc2.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
>I think the best solution to this is to use ":=" for assignment and "==" for
>equality. That way there would be no problem with using the wrong one in the
>wrong context by accident.
>
Not necessary, of course; no *real* programmer would mistype something that
important.  :-)  :-)  :-)   ("What I smiley three times is false!" - not
quite Lewis Carroll.)

My big complaint with :=, though, is that I've never found a keyboard with
both ':' and '=' either both shifted or both unshifted, although I've seen
them in both other possible configurations.  There are workarounds, such as
key mapping or using '#' or something and doing a global replace, but they
aren't as portable or convenient as I'd like.  (Beats "=" and ".EQ.",
though :-)

>-- 
>Peter da Silva.   `-_-'
>+1 713 274 5180.   'U`
><peter@ficc.ferranti.com>

David Thornley

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (08/01/90)

In article <=L-4T-A@ggpc2.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
> I think the best solution to this is to use ":=" for assignment and "==" for
> equality. That way there would be no problem with using the wrong one in the
> wrong context by accident.

Q has a better solution.

  a == b is for comparison. Its value is 1 if they're equal, 0 if not.
  a := b is for assignment. It sets a to b and has value a.
  a = b is for assignment. It sets a to b and has no value.

Advantages over straight ==/:= and over C:

if(a = b) is invalid, and if(a := b) is easy to notice.

You can still use = for normal assignment, so you don't get confused by
the new notation.

The compiler can check that *every* value is used, rather than just
ignoring assignments. a = b := c := d feels and looks right.

---Dan

peter@ficc.ferranti.com (Peter da Silva) (08/01/90)

In article <17559:Aug101:50:5290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> Q has a better solution.

>   a == b is for comparison. Its value is 1 if they're equal, 0 if not.
>   a := b is for assignment. It sets a to b and has value a.
>   a = b is for assignment. It sets a to b and has no value.

Good idea. PL/M (a language with otherwise very little to recommend it) does
something like this (a = b is still for comparison), though it adds the
syntactic sugar:

	a, b, c = d

which is equivalent to:

	a = b := c := d

Interestingly, the PL/M-286 users guide follows this section with a BIG
BLACK BOX warning that:

	a = (x := x + 4) + y * y + x

is ambiguous and "The results depend on too many factors, e.g. the
optimisation level you specify to the compiler."
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
<peter@ficc.ferranti.com>

sommar@enea.se (Erland Sommarskog) (08/02/90)

David H. Thornley (thornley@cs.umn.edu) writes:
>My big complaint with :=, though, is that I've never found a keyboard with
>both ':' and '=' either both shifted or both unshifted, although I've seen

The keyboard on which I type now is configured that way. (VT220
clone, set to Swedish keyboard.)

An aside: right now I'm on a primitive operating system with a
primitive editor, but when using real stuff I set my terminal
in eight-bit mode, leading to that {} takes just as many key-
strokes a begin-end pair. Thankfully I don't use braces much.

-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se
"...take a lesson from the people in Eastern Europe. I mean,
if you can get the Communists out of there we can the get 
Republicans out of here." - Frank Zappa

preston@titan.rice.edu (Preston Briggs) (08/03/90)

>In article <17559:Aug101:50:5290@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:

About his language Q

>>   a == b is for comparison. Its value is 1 if they're equal, 0 if not.
>>   a := b is for assignment. It sets a to b and has value a.
>>   a = b is for assignment. It sets a to b and has no value.


In article <7H+4AM6@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:

About PL/M

>Interestingly, the PL/M-286 users guide follows this section with a BIG
>BLACK BOX warning that:

>	a = (x := x + 4) + y * y + x

>is ambiguous and "The results depend on too many factors, e.g. the
>optimisation level you specify to the compiler."

It would be nicer if you didn't allow side-effects (assignments, 
among other things) in expressions, particularly for optimizers!

Normally, we say: 

	x + y = y + x	where x and y are arbitrary expressions.

With C, Q, and PL/M, this doesn't hold.
E.g.,

	(i := 1) + i is not always equal to i + (i := 1)

Same problems with ++ and -- in C.
Same problem in lots of languages where people write functions
with side-effects.

-- 
Preston Briggs				looking for the great leap forward
preston@titan.rice.edu

norvell@csri.toronto.edu (Theo Norvell) (08/03/90)

In article <1990Aug2.170110.28208@rice.edu> Preston writes:
>
>Normally, we say: 
>
>	x + y = y + x	where x and y are arbitrary expressions.
>
>With C, Q, and PL/M, this doesn't hold.
>E.g.,
>
>	(i := 1) + i is not always equal to i + (i := 1)
>
>Same problems with ++ and -- in C.
>Same problem in lots of languages where people write functions
>with side-effects.

I can't speak for Q or PL/M, but in C this not so.  The order of evaluation
is not specified for the + operator, nor most others (including the assignment
operators). Given arbitrary expressions x and y, (x + y) can be evaluated by
evaluating x first and then y or the other way around and then adding.

Furthermore, the ansi standard makes it clear that when an expression contains
two assignments to the same variable or an assignment and a reference (unless,
of course, the value to be stored depends on the reference), with no intervening
sequence point, the result is not merely one or the other possible result
but entirely undefined.  So in C the expressions
	(i = 1) + i
and
	i = 1 + ++i
are quite undefined.  A correct C implementation could launch a nuclear strike
on 24 Sussex Drive upon evaluating such an expression (whether it does or not
is a ``quality of implementation'' issue). Just because you see such expressions
in other peoples code does not mean they are allowed by the language.

trt@rti.rti.org (Thomas Truscott) (08/03/90)

> >   a == b is for comparison. Its value is 1 if they're equal, 0 if not.
> >   a := b is for assignment. It sets a to b and has value a.
> >   a = b is for assignment. It sets a to b and has no value.
> 
> Good idea. PL/M ... does something like this ...


I like the Q and PL/M features, but they don't stop me from typing:

	a == b + 1;	/* OOPS, I mean't to assign to a */
or
	if (a := b) ..	/* OOPS, I only wanted to compare them */
not to mention
	a = b++ * b++;


What we *really* need are compilers that issue warnings such as:

test.c: line 7: result of comparison unused!

test.c: line 8: assignment result used in boolean context,
	did you mean ((a := b) != 0), or (a == b)?

test.c: line 9: b evaluation order undefined

If our compilers did that there would be much
less debate about = and == and := in the C language.
And fewer frustrated programmers.

	Tom Truscott

peter@ficc.ferranti.com (Peter da Silva) (08/05/90)

In article <3989@rtifs1.UUCP> trt@rti.rti.org (Thomas Truscott) writes:
> I like the Q and PL/M features, but they don't stop me from typing:

> 	a == b + 1;	/* OOPS, I mean't to assign to a */

PL/M will. A naked expression is not a legal PL/M statement. You meant:

	a = b + a;

> 	if (a := b) ..	/* OOPS, I only wanted to compare them */

I think that is only legal is a and b are booleans. In any case, you want:

	if (a = b) ..

Back to the point.

If I was god and got to fix C, I'd make the indirection operator postfix
before playing with assignment and equality.
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
<peter@ficc.ferranti.com>

peter@ficc.ferranti.com (Peter da Silva) (08/08/90)

In article <1990Aug2.170110.28208@rice.edu> preston@titan.rice.edu (Preston Briggs) writes:
> With C, Q, and PL/M, this doesn't hold.

> 	(i := 1) + i is not always equal to i + (i := 1)

Oh, it's worse than that. (i := 1) + i is not always equal to (i := 1) + i,
depending on optimisation level, or (for a sufficiently clever optimiser)
surrounding code. I can even imagine cases where the same expression twice
in a row produces different results.

> Same problems with ++ and -- in C.

And with any function that has a side effect. Like you say...

> Same problem in lots of languages where people write functions
> with side-effects.

As, for example, any object oriented language where objects have internal
state. Like, about all of them. A language that prevents functions from
having side effects is likely to be pretty restrictive. Can you think of
one, other then purely functional languages? Functions couldn't have I/O,
or for that matter call procedures (since procedures can have side effects).
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
<peter@ficc.ferranti.com>

sommar@enea.se (Erland Sommarskog) (08/09/90)

(Reposted because I think first attempt failed. Apologies for any
repetition.)

David H. Thornley (thornley@cs.umn.edu) writes:
>My big complaint with :=, though, is that I've never found a keyboard with
>both ':' and '=' either both shifted or both unshifted, although I've seen

The keyboard on which I type now is configured that way. (VT220
clone, set to Swedish keyboard.)

An aside: right now I'm on a primitive operating system with a
primitive editor, but when using real stuff I set my terminal
in eight-bit mode, leading to that {} takes just as many key-
strokes a begin-end pair. Thankfully I don't use braces much.
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se

preston@titan.rice.edu (Preston Briggs) (08/10/90)

In article <H925S0B@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
>In article <1990Aug2.170110.28208@rice.edu> preston@titan.rice.edu (Preston Briggs) writes:
>> Same problem in lots of languages where people write functions
>> with side-effects.

>As, for example, any object oriented language where objects have internal
>state. Like, about all of them. 

Sure, but "methods" could be divided into "procedures" (with side-effects)
and "functions" (that have no side-effects).

>A language that prevents functions from
>having side effects is likely to be pretty restrictive. Can you think of
>one, other then purely functional languages? Functions couldn't have I/O,
>or for that matter call procedures (since procedures can have side effects).

I believe there was a language called Euclid, perhaps originating at
Waterloo, that had such a restriction.  Probably there are others.

Regardless, you are exactly right -- it is a significant restriction.  
No I/O, no procedure calls (though further functions calls are ok), 
no modification of global variables, no memory allocation.
Sure isn't C!

It means however, that expressions behave more like those idealized
things we learn about in algebra.  When you evaluate an expression
twice in a row, you get the same result.  When you commute commutative
operators, the result doesn't change.  When you re-associate associate
operators, the result doesn't change (in the context of floating-point,
I'm lying).

Optimizers like these features.  Since most languages don't have them,
optimization is restricted in the presence of function calls.
(Apparently, in the case of C, the optimizer is allowed to
do anything, since expressions with side effects are undefined(!).
Remember that "undefined" means the optimizer may fork a game of
chess if it cares to.).

Historically, people don't seem to care.  Almost no languages enforce
such a restriction and most people don't care to discipline themselves.
Nevertheless, side-effects in expressions are ugly.  Functional programming 
fans go further and say "side effects are ugly".  Tastes vary.

-- 
Preston Briggs				looking for the great leap forward
preston@titan.rice.edu

new@ee.udel.edu (Darren New) (08/10/90)

In article <1990Aug9.174513.16437@rice.edu> preston@titan.rice.edu (Preston Briggs) writes:
>(Apparently, in the case of C, the optimizer is allowed to
>do anything, since expressions with side effects are undefined(!).
>Remember that "undefined" means the optimizer may fork a game of
>chess if it cares to.).

Huh?  Do you know C?   Of course expressions with side-effects are
defined.  Where there is *more than one* side effect, the rules are a
little loose on which side effect gets evaluated first.  Not unclear,
but clearly undefined.  However, there are many situations where the
order of side effects *is* defined: for example, all side-effects in
arguments to a function are finished before the function is called.
However, if you say something like (a[i++] = i), the order of
evaluation can change. The compiler may index a with i, add one to i,
and then assign the new i to a[i]; or it may index a with i, add one to
i, and then assign the old i to a[i]; depending on registers available,
optimizations, and so on. Changing a value and using it in the same
expression (except for some very explicit operators) has always been a
no-no in C.  Such expressions have always been illegal; sadly, most
compilers don't seem to bother to check for illegal programs if they
can compile them into *something*.  I don't know: does lint?

(Also, I don't think there is much use in forking a chess game, either
in the optimizer *or* in the optimized code. "Undefined" does not mean
"silly" :-).

			  -- Darren

norvell@csri.toronto.edu (Theo Norvell) (08/10/90)

In article <H925S0B@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:

>In article <1990Aug2.170110.28208@rice.edu> preston@titan.rice.edu (Preston Briggs) writes:
>> With C, Q, and PL/M, this doesn't hold.
>
>> 	(i := 1) + i is not always equal to i + (i := 1)
>
>Oh, it's worse than that. (i := 1) + i is not always equal to (i := 1) + i,
>depending on optimisation level, or (for a sufficiently clever optimiser)
>surrounding code. I can even imagine cases where the same expression twice
>in a row produces different results.

But, as was pointed out, these expressions are not licit in C (even after
changing := to =).  Both lead to undefined behaviour and in that sense
they are equal.  What they are ``equal to'' numerically is as uninteresting
as what they are equal to in Fortran, Cobol, or Lisp.  The situation may be
different in Q or PL/M.

>As, for example, any object oriented language where objects have internal
>state. Like, about all of them.

No problem.  Divide methods into two classes: Functions, which may not alter
the internal state, and Procedures, which may alter the internal state.
Object orientedness is orthogonal to this discussion.

>A language that prevents functions from
>having side effects is likely to be pretty restrictive. Can you think of
>one, other then purely functional languages?

Several.  Euclid, Turing, Cybil.  Ada too, no doubt.  Even Fortran, I think,
though this is not enforced by compilers.  Language designers have long been
aware of the unhealthiness of side effects.

>Functions couldn't have I/O,
>or for that matter call procedures (since procedures can have side effects).

There is no need to ban all procedure calls, only calls that cause side effects.
If you want all potential side effects banned compile time, all calls
in some superset of those that have side effects must be banned, but still
not all calls to all procedures.

Something that would be useful is a notion of a ``benign side effect''.
For example, a storage allocation function (e.g. a cons function) may
have the side effects of shortening a free list or collecting garbage.
But the side effect is likely hidden by a module interface.

Theo Norvell

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (08/19/90)

In article <:1=4K26@ggpc2.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
> In article <3989@rtifs1.UUCP> trt@rti.rti.org (Thomas Truscott) writes:
> > I like the Q and PL/M features, but they don't stop me from typing:
> > 	a == b + 1;	/* OOPS, I mean't to assign to a */
> PL/M will. A naked expression is not a legal PL/M statement.

It's legal in Q, but the compiler gives you a warning. That's the
biggest advantage of having both := and = for assignment: the compiler
can reasonably check that every value is used, without special-casing
equality the way C compilers do.

> > 	if (a := b) ..	/* OOPS, I only wanted to compare them */
> I think that is only legal is a and b are booleans.

This is legal in Q, but again the compiler gives you a warning.

> If I was god and got to fix C, I'd make the indirection operator postfix
> before playing with assignment and equality.

Right now, Q accepts both *p/&x and p^/x@. The macro processor should
end up powerful enough to eliminate two of the four from the base
language.

---Dan

peter@ficc.ferranti.com (Peter da Silva) (08/20/90)

In article <2538:Aug1914:03:0790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> Right now, Q accepts both *p/&x and p^/x@.

I dig the p^ bit, but x@ is a bit odd (@ is used in other contexts, such as
some assemblers, as an indirection operator).

Since you're overloading ^ (with xor, no?), why not just allow * and &
postfix? It's no worse. What about "p^-3"? Is that (p^)-3 or p^(-3).
-- 
Peter da Silva.   `-_-'
+1 713 274 5180.   'U`
peter@ferranti.com (currently not working)
peter@hackercorp.com

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (08/21/90)

In article <+KB5WSF@ggpc2.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes:
> In article <2538:Aug1914:03:0790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> > Right now, Q accepts both *p/&x and p^/x@.
> I dig the p^ bit, but x@ is a bit odd (@ is used in other contexts, such as
> some assemblers, as an indirection operator).

I know, you think @ should replace * everywhere. I just picked a symbol
at random; the alphabet is rather fluid, as Q uses category codes like
TeX. The last stage of design will be a symbol review.

> Since you're overloading ^ (with xor, no?),

No. ^ is gone in favor of xor, at least for the moment.

---Dan