December 09, 2011
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
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
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
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
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
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
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
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
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
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.