July 15, 2005
Uwe Salomon wrote:
<snip>
> If you have this expression:
> 
> b = b + c;
> 
> Compiled it will look somehow like this:
> 
> make a copy of b
> add c to the copy
> store the result to b
> 
> The other variant:
> 
> b += c;
> 
> Looks like this when compiled:
> 
> add c to b
> 
> See the difference? In the first variant b is "evaluated" twice.
<snip>

Unless you add the words "except that b is only evaluated once" to the first explanation.  Indeed, this is how it's explained in the spec if you care to read it.

Moreover, even if &&= ||= were a special case of being not so easily explainable in words, it would still be equally implementable.

Stewart.

-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/M d- s:- a->--- UB@ P+ L E@ W++@ N+++ o K- w++@ O? M V? PS- PE- Y? PGP- t- 5? X? R b DI? D G e++>++++ h-- r-- !y
------END GEEK CODE BLOCK------

My e-mail is valid but not my primary mailbox.  Please keep replies on the 'group where everyone may benefit.
July 18, 2005
/// I'm discussing C: AFIK applies equally to D

b += c; // LHS evaluated only once.

If 'b' is a simple (non-class) variable, there's no difference between "b += c" and "b = b + c".

The difference is important when there is a calculation involved in finding the address of the lvalue, and that calculation has (or may
have) side-effects.

   *get_ptr(x)  += 2;

vs.
   *get_ptr(x) = *get_ptr(x) + 2;

the first example makes only 1 call to get_ptr(), the second
will make two. The order in which the two calls are made is
not specified by the C language.

Or,
	a[ i++ ] += 3;
// NOT the same as
	a[ i++ ] = a[i++] + 3;
(the second example is improper C, since the two references to i are
not well-defined relative to the modifications of i)

'calculating' the address of a local variable by adding a constant
to the frame pointer doesn't count, since the result cannot
change during the  execution of a single statement; the
compiler is perfectly free to do that once  for
'b = b+c', or do it twice for 'b+=c'.

[Note: I remember some cheesy old C compilers which generated code
directly out of the parser, such that 'b+=c' would be smaller than
'b = b + c', since the compiler calculated the address of local 'b'
twice in the second case. That is not a language issue, it's a cheesy
compiler issue. The same compiler generated less code for '++i;' than
for 'i++;', enough said ]

Another example:

	arr[i+2] += 4;
	arr[i+2] = arr[i+2] + 4;

Both have the same effect. They may generate different code, depending
on the compiler. But they may not. The distinction between + and +=
doesn't extend to that.

Stewart Gordon wrote:

> Uwe Salomon wrote:
> <snip>
> 
>> If you have this expression:
>>
>> b = b + c;
>>
>> Compiled it will look somehow like this:
>>
>> make a copy of b
>> add c to the copy
>> store the result to b
>>
>> The other variant:
>>
>> b += c;
>>
>> Looks like this when compiled:
>>
>> add c to b
>>
>> See the difference? In the first variant b is "evaluated" twice.
> 
> <snip>
> 
> Unless you add the words "except that b is only evaluated once" to the first explanation.  Indeed, this is how it's explained in the spec if you care to read it.
> 
> Moreover, even if &&= ||= were a special case of being not so easily explainable in words, it would still be equally implementable.
> 
> Stewart.
> 
July 18, 2005
Uwe Salomon wrote:

>>> With integers you have to use the long form, because all op= variants  are guaranteed to evaluate the lvalue only once.  This is not possible  for &&= with, say, an uint.
>>
>>
>> What do you mean by this?
> 
> 
> Look at the code equivalent you have given yourself:
> 
>> Really
>>
>>      b &&= c;
>>
>> should be equivalent to
>>
>>      if (b) b = c;
> 
> 
> if (b) -- first access to b
> b = c -- second access to b
> 
> But the operators +=  -=  |=  etc. should evaluate b only once, not twice.
> 
> By the way, b &&= c should mean something like this:
> 
> if (b)
>   b = (c != 0);
> 
 the 'evaluated once' only is meaningful when the LHS has an address which must be calculated, and its calculation may have side-effects.
The calculation will only be done once.

  {bit *  bptr = &b;		// the 'evaluated once' means this
  if (*bptr)
   *bptr = (c != 0);
  }

I remember a discussion about &&= and ||= about 20 years ago on comp.lang.c, when the ISO standard was being drafted. Yes, they
could be done, but they're rather weird; what about


  int b = 4;
  int c = ...; // doesn't matter

  b ||= c;

should this leave 'b' as 4, since the evaluation was
short-circuited due to b!=0 ?? This is what has been proposed
in this thread. Or should it set 'b' to 1, which
is what b = b||c does?

no thanks. Such an operator would be misunderstood out of proportion
to its usefulness, no matter how it is defined.

 - greg



July 18, 2005
On Mon, 18 Jul 2005 17:02:24 -0400, Greg Smith wrote:

> Uwe Salomon wrote:
> 
>>>> With integers you have to use the long form, because all op= variants  are guaranteed to evaluate the lvalue only once.  This is not possible  for &&= with, say, an uint.
>>>
>>>
>>> What do you mean by this?
>> 
>> 
>> Look at the code equivalent you have given yourself:
>> 
>>> Really
>>>
>>>      b &&= c;
>>>
>>> should be equivalent to
>>>
>>>      if (b) b = c;
>> 
>> 
>> if (b) -- first access to b
>> b = c -- second access to b
>> 
>> But the operators +=  -=  |=  etc. should evaluate b only once, not twice.
>> 
>> By the way, b &&= c should mean something like this:
>> 
>> if (b)
>>   b = (c != 0);
>> 
>   the 'evaluated once' only is meaningful when the LHS has an address
> which must be calculated, and its calculation may have side-effects.
> The calculation will only be done once.
> 
>    {bit *  bptr = &b;		// the 'evaluated once' means this
>    if (*bptr)
>     *bptr = (c != 0);
>    }
> 
> I remember a discussion about &&= and ||= about 20 years ago on comp.lang.c, when the ISO standard was being drafted. Yes, they could be done, but they're rather weird; what about
> 
> 
>    int b = 4;
>    int c = ...; // doesn't matter
> 
>    b ||= c;
> 
> should this leave 'b' as 4, since the evaluation was
> short-circuited due to b!=0 ?? This is what has been proposed
> in this thread. Or should it set 'b' to 1, which
> is what b = b||c does?
> 
> no thanks. Such an operator would be misunderstood out of proportion to its usefulness, no matter how it is defined.

LOL... In 'my world' both these would not be allowed because you can't OR non-booleans.

This would be okay ...
  bool b,c;
  . . .
  b = b || c;

But this would be just silly...

  int b,c;
  . . .
  b = b || c;

You could do this though ...

  b = cast(int) ((b != 0) || (c != 0));

But I digress ... D isn't my perfect language, nor will it ever be.

-- 
Derek Parnell
Melbourne, Australia
19/07/2005 7:46:13 AM
July 19, 2005
> LOL... In 'my world' both these would not be allowed because you can't OR
> non-booleans.
>
>   b = cast(int) ((b != 0) || (c != 0));

Hmm. Your world seems to be cluttered with parentheses and casts... Not sure if this is the way to go. :)

Ciao
uwe
July 19, 2005
On Tue, 19 Jul 2005 07:41:02 +0200, Uwe Salomon wrote:

>> LOL... In 'my world' both these would not be allowed because you can't OR non-booleans.
>>
>>   b = cast(int) ((b != 0) || (c != 0));
> 
> Hmm. Your world seems to be cluttered with parentheses and casts... Not sure if this is the way to go. :)

LOL.

My point however was that the OP was dealing with numbers, and why does anybody want to logically-or numbers? Booleans I can understand, but numbers? Doesn't make sense to me. It as silly as asking for the square root of "ABC".

The point with casts and parenthesizes, is that if you really, really needed to do this, then your code should have obvious flashing warning signs around it.

-- 
Derek
Melbourne, Australia
19/07/2005 3:48:07 PM
July 19, 2005
> My point however was that the OP was dealing with numbers, and why does
> anybody want to logically-or numbers? Booleans I can understand, but
> numbers? Doesn't make sense to me. It as silly as asking for the square
> root of "ABC".

I have often seen things like this when dealing with return values or lengths. API functions from Windows or libc or whatever often return a status code that is of type int. If zero is used to signal an error, and a nonzero value for success, you can write things like this:

if (write(f, "xyz") && read(g, &i))
  printf("success!");

The same goes for pointers and lengths:

if (someObj)
  delete someObj;

Though i must admit that i often write the full expressions because i don't like this kind of abbreviations.

> The point with casts and parenthesizes, is that if you really, really
> needed to do this, then your code should have obvious flashing warning
> signs around it.

Nah, that's too much.

Ciao
uwe
1 2
Next ›   Last »