View mode: basic / threaded / horizontal-split · Log in · Help
December 09, 2011
Re: Comma operator = broken design
On Fri, 09 Dec 2011 09:25:34 -0500, Regan Heath <regan@netmail.co.nz>  
wrote:

> On Fri, 09 Dec 2011 13:42:34 -0000, Timon Gehr <timon.gehr@gmx.ch> wrote:
>> On 12/09/2011 02:28 PM, Regan Heath wrote:
>>> On Fri, 09 Dec 2011 13:15:47 -0000, Timon Gehr <timon.gehr@gmx.ch>  
>>> wrote:
>>>> On 12/09/2011 01:36 PM, Regan Heath wrote:
>>>>> 4)
>>>>>
>>>>>> if (std.ascii.toLower(p.front) == 'n' &&
>>>>>> (p.popFront(), std.ascii.toLower(p.front) == 'f') &&
>>>>>> (p.popFront(), p.empty))
>>>>>
>>>>> 'if' statements with side effects are yuck. I prefer the check for  
>>>>> error
>>>>> and bail style but you could use multiple layers of 'if' instead..
>>>>>
>>>>> if (std.ascii.toLower(p.front) != 'n') //error handling
>>>>> p.popFront();
>>>>> if (std.ascii.toLower(p.front) != 'f') //error handling
>>>>> p.popFront();
>>>>> if (!p.empty) //error handling
>>>>>
>>>>
>>>> Your '//error handling' shortcut hides relevant information.
>>>
>>> What information? With context I could be more specific about what to  
>>> do
>>> for each/all.
>>
>> You can always grep the Phobos source to get context. Basically, you  
>> are suggesting to replace the comma operator with gotos:
>>
>>      case 'i': case 'I':
>>          p.popFront();
>>          if (std.ascii.toLower(p.front) == 'n' &&
>>                  (p.popFront(), std.ascii.toLower(p.front) == 'f') &&
>> 	        (p.popFront(), p.empty))
>>          {
>>              // 'inf'
>>              return sign ? -Target.infinity : Target.infinity;
>>          }
>>          goto default;
>>      default: {}
>>      }
>
> If using 'goto' is the 'correct' agreed upon style for phobos then,  
> yes.  It's not my personal preference however and I'd probably refactor  
> it further if it was my own code.
>

goto in this case is acceptable.  It's a goto case statement, which  
technically should be required for fall-through.

>>>>> 5)
>>>>>
>>>>>> enforce((p.popFront(), !p.empty && std.ascii.toUpper(p.front) ==  
>>>>>> 'A')
>>>>>> && (p.popFront(), !p.empty && std.ascii.toUpper(p.front) == 'N'),
>>>>>> new ConvException("error converting input to floating point"));
>>>>>
>>>>> This is blatant enforce abuse IMO..
>>>>>
>>>>> p.popFront();
>>>>> if(p.empty || std.ascii.toUpper(p.front) != 'A'))
>>>>> throw new ConvException("error converting input to floating point"));
>>>>> p.popFront();
>>>>> if(p.empty || std.ascii.toUpper(p.front) != 'N'))
>>>>> throw new ConvException("error converting input to floating point"));
>>>>>
>>>>
>>>> This is blatant code duplication.
>>>
>>> Of the throw line? Sure, and you can re-write with nested 'if' if you
>>> prefer. I prefer the code duplication tho.
>>>
>>
>> Code duplication is very error prone. Furthermore I never ever want to  
>> duplicate _error handling_ code. That just clutters up the generated  
>> machine code if the compiler does not manage to reverse engineer and  
>> generate the proper solution.
>
> I can't comment on the machine code aspect.  I don't find this  
> particular duplication error prone, but if you do you can use the nested  
> if that I've already mentioned.

This case is a perfect example of what is right and wrong with the comma  
operator.

With the comma operator, the single statement avoids code duplication,  
which is good for maintenance.  However, it's extremely hard to see what's  
going on.  Timon, please accept that you may be one of the few who reads  
that statement and sees perfectly what's happening, I needed to read  
Regan's version to understand what it does without hurting my head too  
much.

My opinion?  I think it's better written like this:

p.popFront();
bool bad = void;
if(!(bad = p.empty || std.ascii.toUpper(p.front) != 'A'))
{
   p.popFront();
   bad = p.empty || std.ascii.toUpper(p.front) != 'N';
}
if(bad)
   throw new ConvException("error converting input to floating point");

And I'd probably reread it again, and throw in some comments to help me  
remember what the f*** I was doing :)

I don't see a smaller solution, or one that doesn't use a temporary,  
without using the comma operator or duplicating the throw/enforce call.

-Steve
December 09, 2011
Re: Comma operator = broken design
On Fri, 09 Dec 2011 14:54:16 -0000, Timon Gehr <timon.gehr@gmx.ch> wrote:
>>>>>> 10)
>>>>>>
>>>>>>> return
>>>>>>> c <= 0x7F ? 1
>>>>>>> : c <= 0x7FF ? 2
>>>>>>> : c <= 0xFFFF ? 3
>>>>>>> : c <= 0x10FFFF ? 4
>>>>>>> : (assert(false), 6);
>>>>>>
>>>>>> *Much* clearer with the rewrite..
>>>>>>
>>>>>> assert(c <= 0x10FFFF);
>>>>>> return
>>>>>> c <= 0x7F ? 1
>>>>>> : c <= 0x7FF ? 2
>>>>>> : c <= 0xFFFF ? 3
>>>>>> : c <= 0x10FFFF ? 4
>>>>>> : 6;
>>>>>>
>>>>>
>>>>> This is a *much* better rewrite:
>>>>> assert(c <= 0x10FFFF);
>>>>> return
>>>>> c <= 0x7F ? 1
>>>>> : c <= 0x7FF ? 2
>>>>> : c <= 0xFFFF ? 3
>>>>> : 4;
>>>>
>>>> Again, I was missing context.. is the return value of 6 not required  
>>>> in
>>>> release mode?
>>>
>>> I was joking here. Your 'rewrite' of the original example changed its
>>> release mode semantics, therefore I did the same thing.
>>
>> My version performs the assert in all cases, throws an assert error in
>> the same/error cases, and still returns the correct/original values. The
>> only change is performing the assert in all cases, so I don't see how
>> that is a problem. Yours however is entirely broken (assuming the return
>> value of 6 is desired/required).
>>
>> R
>>
>
> What you might be missing is that assert(false) is not compiled out in  
> release mode. It emits a 'hlt' instruction which kills your program.  
> However, your assert(c <= 0x10FFFF); will be removed in release mode.

I was indeed missing that.  I couldn't find anything about it on the  
website. :)

R

-- 
Using Opera's revolutionary email client: http://www.opera.com/mail/
December 09, 2011
Re: Comma operator = broken design
On 12/09/2011 04:37 PM, Regan Heath wrote:
> On Fri, 09 Dec 2011 14:54:16 -0000, Timon Gehr <timon.gehr@gmx.ch> wrote:
>>>>>>> 10)
>>>>>>>
>>>>>>>> return
>>>>>>>> c <= 0x7F ? 1
>>>>>>>> : c <= 0x7FF ? 2
>>>>>>>> : c <= 0xFFFF ? 3
>>>>>>>> : c <= 0x10FFFF ? 4
>>>>>>>> : (assert(false), 6);
>>>>>>>
>>>>>>> *Much* clearer with the rewrite..
>>>>>>>
>>>>>>> assert(c <= 0x10FFFF);
>>>>>>> return
>>>>>>> c <= 0x7F ? 1
>>>>>>> : c <= 0x7FF ? 2
>>>>>>> : c <= 0xFFFF ? 3
>>>>>>> : c <= 0x10FFFF ? 4
>>>>>>> : 6;
>>>>>>>
>>>>>>
>>>>>> This is a *much* better rewrite:
>>>>>> assert(c <= 0x10FFFF);
>>>>>> return
>>>>>> c <= 0x7F ? 1
>>>>>> : c <= 0x7FF ? 2
>>>>>> : c <= 0xFFFF ? 3
>>>>>> : 4;
>>>>>
>>>>> Again, I was missing context.. is the return value of 6 not
>>>>> required in
>>>>> release mode?
>>>>
>>>> I was joking here. Your 'rewrite' of the original example changed its
>>>> release mode semantics, therefore I did the same thing.
>>>
>>> My version performs the assert in all cases, throws an assert error in
>>> the same/error cases, and still returns the correct/original values. The
>>> only change is performing the assert in all cases, so I don't see how
>>> that is a problem. Yours however is entirely broken (assuming the return
>>> value of 6 is desired/required).
>>>
>>> R
>>>
>>
>> What you might be missing is that assert(false) is not compiled out in
>> release mode. It emits a 'hlt' instruction which kills your program.
>> However, your assert(c <= 0x10FFFF); will be removed in release mode.
>
> I was indeed missing that. I couldn't find anything about it on the
> website. :)
>
> R
>

http://d-programming-language.org/expression.html#AssertExpression
December 09, 2011
Re: Comma operator = broken design
On Friday, December 09, 2011 13:00:57 Timon Gehr wrote:
> On 12/09/2011 10:26 AM, Jonathan M Davis wrote:
> > On Friday, December 09, 2011 10:19:18 Don wrote:
> >> Are there any cases where you're using comma outside of for loops?
> >> I wonder how much would break if were made illegal everywhere else.
> > 
> > I'm sure that it would break code, but most people consider it bad
> > practice to use the comma operator for much outside of for loops.
> 
> 'most people'?
> 
> > Occasionally, it's
> > useful to use one in an expression, but on the whole, it's just
> > confusing and error-prone.
> 
> It is confusing to people who don't know the language. It is a simple
> construct. In my experience, it is certainly not error prone. If you are
> aware that such an operator exists.
> 
> > And while it might break code to make the comma operator illegal
> > outside of for loops, I would expect that fixing the broken code would
> > generally be rather trivial.
> 
> Sure.
> 
> > The resulting code may not be as compact, but it
> > wouldn't be hard to write.
> 
> It would be a PITA in some cases.
> 
> > And unless you're dealing with a programmer who
> > uses it uncommonly often, not much code is going to break.
> 
> I _am_ such a programmer.

In my experience, someone like you who uses the comma operator outside of for 
loops much at all is incredibly rare. It's far more typical to consider the 
comma operator confusing and error-prone than it is to use it frequently.

- Jonathan M Davis
December 09, 2011
Re: Comma operator = broken design
On Friday, December 09, 2011 12:36:25 Regan Heath wrote:
> On Fri, 09 Dec 2011 11:39:55 -0000, Timon Gehr <timon.gehr@gmx.ch> wrote:
> > These are the occurences of the comma operator in directory 'std':
> Here is my /very/ quick re-write of each without looking at the context of
> each snippet. There may be much better re-writes in context. Re-writing
> this was problematic /because/ the comma operator makes things that much
> more confusing to me. Especially example #5 below where the last ,
> actually separates enforce parameters!
> 
> 1)
> 
> > return r2.empty ? (r1 = r, true) : false;
> 
> if (!r2.empty) return false;
> r1 = r;
> return true;

Actually, that particular usage of the comma operator makes me almost want to 
use it that way. It manages to take one of the type of statements that always 
irritates me when it's multiple lines and make it a single line.

- Jonathan M Davis
December 10, 2011
Re: Comma operator = broken design
On Fri, 09 Dec 2011 01:20:45 -0500, Kagamin <spam@here.lot> wrote:

> On Thursday, 8 December 2011 at 17:18:57 UTC, Joshua Reusch wrote:
>>
>>> Ahem. So are you suggesting that (a,b) means a tuple
>>> everywhere but in a
>>> for loop, where it is used to separate two statements?
>>
>> If we use the comma operator only for tuples, there needn't to
>> be a special case for loops:
>>
>> for(x, y = 0 , 100; x < y ; x, y += 1,-1) { ... }
>
> for(int x, y = 0 , 100; x < y ; x, y += 1,-1) { ... }
>
> ?
>

Here's how I understood it:

int x,y; // Defined somewhere in the code above

for( (x,y) = (0,100); x < y ; (x,y) += (1,-1) ) { ... }

So you have variable capture, assignment and add-assign happening.
December 10, 2011
Re: Comma operator = broken design
On Fri, 09 Dec 2011 00:27:39 -0500, so <so@so.so> wrote:
> On Fri, 09 Dec 2011 06:26:27 +0200, Robert Jacques <sandford@jhu.edu>
> wrote:
>
>>> So it clashes with another thing about D, pragmatism.
>> I'm not sure what you mean by that.
>
> It was/is one of the defining points of D AFAIK.
> More than being theoretical it chose to be pragmatic, to solve the
> problems we face day to day.
> For the case at hand; Say uninitialized variables in C are undefined but
> all the compilers do
> the same thing that makes it in practice defined. So the below line should
> execute same on all compilers.
>
> 	type a;
>
> Same applies to the extensions supported in all major compilers which is
> absent in language spec.
> If compilers don't support, they can't sell.
>
> To the point. If you want to keep B-D rule with the presence of such big
> design mistakes (C), you are not being pragmatic at all.

Interesting point. I agree with D being a very pragmatic language (it's one of my favorite things about it), but I come to a different conclusion. The ability to copy and paste code, i.e. source compatible, is one of the most pragmatic things a language can do. And, unlike C++, the B-D rule allows D to break compatibility and therefore convert design mistakes into invalid syntax. However, this is at the cost of preventing the invalidated syntax from being re-used for other means.
December 10, 2011
Re: Comma operator = broken design
On Friday, December 09, 2011 20:18:36 Robert Jacques wrote:
> On Fri, 09 Dec 2011 01:20:45 -0500, Kagamin <spam@here.lot> wrote:
> > On Thursday, 8 December 2011 at 17:18:57 UTC, Joshua Reusch wrote:
> >>> Ahem. So are you suggesting that (a,b) means a tuple
> >>> everywhere but in a
> >>> for loop, where it is used to separate two statements?
> >> 
> >> If we use the comma operator only for tuples, there needn't to
> >> be a special case for loops:
> >> 
> >> for(x, y = 0 , 100; x < y ; x, y += 1,-1) { ... }
> > 
> > for(int x, y = 0 , 100; x < y ; x, y += 1,-1) { ... }
> > 
> > ?
> 
> Here's how I understood it:
> 
> int x,y; // Defined somewhere in the code above
> 
> for( (x,y) = (0,100); x < y ; (x,y) += (1,-1) ) { ... }
> 
> So you have variable capture, assignment and add-assign happening.

I'd _hate_ to be restricted to doing the same operation in the 3rd portion of 
a for loop for all of its parts. The comma operator is _perfect_ for there, 
and I wouldn't want to see its behavior changed there regardless. e.g. things 
like this should continue to be perfectly possible and legal

for(; cond; ++x, y *= 2) {}

Tuples do _not_ have the proper semantics for a for loop. It would be one 
thing for the comma operator were to go away in the general case, but it would 
be horrible IMHO for its behavior to be changed in for loops - be it in an 
effort to make it act like it's using tuples or any other reason.

- Jonathan M Davis
December 11, 2011
Re: Comma operator = broken design
On 10-12-2011 02:39, Jonathan M Davis wrote:
> On Friday, December 09, 2011 20:18:36 Robert Jacques wrote:
>> On Fri, 09 Dec 2011 01:20:45 -0500, Kagamin<spam@here.lot>  wrote:
>>> On Thursday, 8 December 2011 at 17:18:57 UTC, Joshua Reusch wrote:
>>>>> Ahem. So are you suggesting that (a,b) means a tuple
>>>>> everywhere but in a
>>>>> for loop, where it is used to separate two statements?
>>>>
>>>> If we use the comma operator only for tuples, there needn't to
>>>> be a special case for loops:
>>>>
>>>> for(x, y = 0 , 100; x<  y ; x, y += 1,-1) { ... }
>>>
>>> for(int x, y = 0 , 100; x<  y ; x, y += 1,-1) { ... }
>>>
>>> ?
>>
>> Here's how I understood it:
>>
>> int x,y; // Defined somewhere in the code above
>>
>> for( (x,y) = (0,100); x<  y ; (x,y) += (1,-1) ) { ... }
>>
>> So you have variable capture, assignment and add-assign happening.
>
> I'd _hate_ to be restricted to doing the same operation in the 3rd portion of
> a for loop for all of its parts. The comma operator is _perfect_ for there,
> and I wouldn't want to see its behavior changed there regardless. e.g. things
> like this should continue to be perfectly possible and legal
>
> for(; cond; ++x, y *= 2) {}
>
> Tuples do _not_ have the proper semantics for a for loop. It would be one
> thing for the comma operator were to go away in the general case, but it would
> be horrible IMHO for its behavior to be changed in for loops - be it in an
> effort to make it act like it's using tuples or any other reason.
>
> - Jonathan M Davis

Indeed, having the comma operator in for loops is perfectly normal; even 
C# has this.

- Alex
December 12, 2011
Re: Comma operator = broken design
On Sun, 11 Dec 2011 06:21:51 -0500, Alex Rønne Petersen <xtzgzorex@gmail.com> wrote:

> On 10-12-2011 02:39, Jonathan M Davis wrote:
>> On Friday, December 09, 2011 20:18:36 Robert Jacques wrote:
>>> On Fri, 09 Dec 2011 01:20:45 -0500, Kagamin<spam@here.lot>  wrote:
>>>> On Thursday, 8 December 2011 at 17:18:57 UTC, Joshua Reusch wrote:
>>>>>> Ahem. So are you suggesting that (a,b) means a tuple
>>>>>> everywhere but in a
>>>>>> for loop, where it is used to separate two statements?
>>>>>
>>>>> If we use the comma operator only for tuples, there needn't to
>>>>> be a special case for loops:
>>>>>
>>>>> for(x, y = 0 , 100; x<  y ; x, y += 1,-1) { ... }
>>>>
>>>> for(int x, y = 0 , 100; x<  y ; x, y += 1,-1) { ... }
>>>>
>>>> ?
>>>
>>> Here's how I understood it:
>>>
>>> int x,y; // Defined somewhere in the code above
>>>
>>> for( (x,y) = (0,100); x<  y ; (x,y) += (1,-1) ) { ... }
>>>
>>> So you have variable capture, assignment and add-assign happening.
>>
>> I'd _hate_ to be restricted to doing the same operation in the 3rd portion of
>> a for loop for all of its parts. The comma operator is _perfect_ for there,
>> and I wouldn't want to see its behavior changed there regardless. e.g. things
>> like this should continue to be perfectly possible and legal
>>
>> for(; cond; ++x, y *= 2) {}
>>
>> Tuples do _not_ have the proper semantics for a for loop. It would be one
>> thing for the comma operator were to go away in the general case, but it would
>> be horrible IMHO for its behavior to be changed in for loops - be it in an
>> effort to make it act like it's using tuples or any other reason.
>>
>> - Jonathan M Davis
>
> Indeed, having the comma operator in for loops is perfectly normal; even
> C# has this.
>
> - Alex
>

A lot (all?) of for loop use cases seem to actually work in tuple form. For instance,

for(; cond; tuple(++x, y *= 2) ) {}

Will behave as expected, although there might be a performance issue.
2 3 4 5 6 7
Top | Discussion index | About this forum | D home