www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - comma operator causes hard to spot bugs

reply Benjamin Thaut <code benjamin-thaut.de> writes:
Hi,
I just had a bug due to the unitentional usage of the comma operator. So 
I'm wondering if there could something be done so that the compiler 
prevents something like this:

memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof), 
InitializeMemoryWith.NOTHING);

This first excutes AllocateMemory, then throws away the result and then 
casts the enum InitializeMemory.NOTHING value to a pointer, which will 
always result in a null pointer. This took me quite some time to spot.
What I actually wanted to do:

memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof, 
InitializeMemoryWith.NOTHING));

1) So is it actually neccessary that enums can be casted directly to 
pointers?
2) Is the functionality provided by the comma operator actually worth 
the bugs it causes?

Kind Regards
Benjamin Thaut
Apr 21 2012
next sibling parent reply =?ISO-8859-15?Q?Alex_R=F8nne_Petersen?= <xtzgzorex gmail.com> writes:
On 21-04-2012 14:23, Benjamin Thaut wrote:
 Hi,
 I just had a bug due to the unitentional usage of the comma operator. So
 I'm wondering if there could something be done so that the compiler
 prevents something like this:

 memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof),
 InitializeMemoryWith.NOTHING);

 This first excutes AllocateMemory, then throws away the result and then
 casts the enum InitializeMemory.NOTHING value to a pointer, which will
 always result in a null pointer. This took me quite some time to spot.
 What I actually wanted to do:

 memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof,
 InitializeMemoryWith.NOTHING));

 1) So is it actually neccessary that enums can be casted directly to
 pointers?
 2) Is the functionality provided by the comma operator actually worth
 the bugs it causes?
No. It's an abomination, and it blocks more novel/interesting language design opportunities.
 Kind Regards
 Benjamin Thaut
-- - Alex
Apr 21 2012
parent reply Jonathan M Davis <jmdavisProg gmx.com> writes:
On Saturday, April 21, 2012 14:25:14 Alex R=C3=B8nne Petersen wrote:
 No. It's an abomination, and it blocks more novel/interesting languag=
e
 design opportunities.
There have been discussions about the comma operator before. I don't ex= pect=20 that it's going anywhere, even though there are plenty of people who wo= uld=20 love to see it gone. - Jonathan M Davis
Apr 21 2012
next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 21/04/2012 14:51, Jonathan M Davis a écrit :
 On Saturday, April 21, 2012 14:25:14 Alex Rønne Petersen wrote:
 No. It's an abomination, and it blocks more novel/interesting language
 design opportunities.
There have been discussions about the comma operator before. I don't expect that it's going anywhere, even though there are plenty of people who would love to see it gone. - Jonathan M Davis
Add me on the list.
Apr 21 2012
prev sibling parent reply "bearophile" <bearophileHUGS lycos.com> writes:
Jonathan M Davis:

 There have been discussions about the comma operator before. I 
 don't expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar(); While this is sometimes a trap: auto x = foo(), bar(); So maybe it's enough to disallow using the last expression of a comma sequence as result of the whole expression? I don't know. I almost never use commas for such purposes. What are the use case for those commas? Bye, bearophile
Apr 21 2012
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/21/2012 06:54 PM, bearophile wrote:
 Jonathan M Davis:

 There have been discussions about the comma operator before. I don't
 expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar(); While this is sometimes a trap: auto x = foo(), bar();
This is not valid code.
 So maybe it's enough to disallow using the last expression of a comma
 sequence as result of the whole expression?  I don't know. I almost never
 use commas for such purposes. What are the use case for those commas?

 Bye,
 bearophile
if(r.front == 'a' && (r.popFront(), r.front) == 'b') { ... } There are a few similar usages in Phobos. If comma was to be used as a tuple constructor instead, those could be replaced by ( , )[$-1].
Apr 21 2012
next sibling parent travert phare.normalesup.org (Christophe) writes:
Timon Gehr , dans le message (digitalmars.D:164810), a écrit :
 
 There are a few similar usages in Phobos. If comma was to be used as a 
 tuple constructor instead, those could be replaced by ( , )[$-1].
That would be nice. -- Christophe
Apr 21 2012
prev sibling next sibling parent deadalnix <deadalnix gmail.com> writes:
Le 21/04/2012 20:25, Timon Gehr a écrit :
 On 04/21/2012 06:54 PM, bearophile wrote:
 Jonathan M Davis:

 There have been discussions about the comma operator before. I don't
 expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar(); While this is sometimes a trap: auto x = foo(), bar();
This is not valid code.
 So maybe it's enough to disallow using the last expression of a comma
 sequence as result of the whole expression? I don't know. I almost never
 use commas for such purposes. What are the use case for those commas?

 Bye,
 bearophile
if(r.front == 'a' && (r.popFront(), r.front) == 'b') { ... } There are a few similar usages in Phobos. If comma was to be used as a tuple constructor instead, those could be replaced by ( , )[$-1].
That is better.
Apr 22 2012
prev sibling next sibling parent Andrej Mitrovic <andrej.mitrovich gmail.com> writes:
On 4/21/12, Timon Gehr <timon.gehr gmx.ch> wrote:
 those could be replaced by ( , )[$-1].
Also known as indexOpRightButtCheek().
Apr 22 2012
prev sibling parent reply "Martin Nowak" <dawg dawgfoto.de> writes:
 if(r.front == 'a' && (r.popFront(), r.front) == 'b') { ... }

 There are a few similar usages in Phobos. If comma was to be used as a  
 tuple constructor instead, those could be replaced by ( , )[$-1].
Tuples with void elements? And if the first exp had a value one wouldn't like to pay for the copying.
Apr 23 2012
parent Timon Gehr <timon.gehr gmx.ch> writes:
On 04/24/2012 03:21 AM, Martin Nowak wrote:
 if(r.front == 'a' && (r.popFront(), r.front) == 'b') { ... }

 There are a few similar usages in Phobos. If comma was to be used as a
 tuple constructor instead, those could be replaced by ( , )[$-1].
Tuples with void elements?
Yes. They behave similar to void.
 And if the first exp had a value one wouldn't like to pay for the copying.
How would this require copying? D language tuples already work in a way that would make (,)[$-1] completely equivalent to what (,) does now.
Apr 23 2012
prev sibling next sibling parent reply deadalnix <deadalnix gmail.com> writes:
Le 21/04/2012 18:54, bearophile a écrit :
 Jonathan M Davis:

 There have been discussions about the comma operator before. I don't
 expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar();
This is completely redundant with foo(); bar(); I see no benefit from being able to do this.
Apr 22 2012
parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 04/23/2012 01:56 AM, deadalnix wrote:
 Le 21/04/2012 18:54, bearophile a écrit :
 Jonathan M Davis:

 There have been discussions about the comma operator before. I don't
 expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar();
This is completely redundant with foo(); bar();
Not completely, you also need { } if(qux()) foo(), bar();
 I see no benefit from being able to do this.
Apr 23 2012
parent reply "CTFE-4-the-win" <CTFE 4the.win> writes:
On Monday, 23 April 2012 at 08:08:52 UTC, Timon Gehr wrote:
 On 04/23/2012 01:56 AM, deadalnix wrote:
 Le 21/04/2012 18:54, bearophile a écrit :
 Jonathan M Davis:

 There have been discussions about the comma operator before. 
 I don't
 expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar();
This is completely redundant with foo(); bar();
Not completely, you also need { } if(qux()) foo(), bar();
 I see no benefit from being able to do this.
I think the most common use-case for the , operator is in the "increment part" of for loops... but this could of course be special-cased to still be allowed...
Apr 23 2012
parent =?UTF-8?B?QWxleCBSw7hubmUgUGV0ZXJzZW4=?= <xtzgzorex gmail.com> writes:
On 23-04-2012 11:38, CTFE-4-the-win wrote:
 On Monday, 23 April 2012 at 08:08:52 UTC, Timon Gehr wrote:
 On 04/23/2012 01:56 AM, deadalnix wrote:
 Le 21/04/2012 18:54, bearophile a écrit :
 Jonathan M Davis:

 There have been discussions about the comma operator before. I don't
 expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar();
This is completely redundant with foo(); bar();
Not completely, you also need { } if(qux()) foo(), bar();
 I see no benefit from being able to do this.
I think the most common use-case for the , operator is in the "increment part" of for loops... but this could of course be special-cased to still be allowed...
Which is what the rest of the world's programming languages (other than C and C++) do. -- - Alex
Apr 23 2012
prev sibling parent reply "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 21 April 2012 at 16:54:49 UTC, bearophile wrote:
 Jonathan M Davis:

 There have been discussions about the comma operator before. I 
 don't expect that it's going anywhere,
Maybe there are intermediate solutions between keeping wild commas in D and disallowing them fully. I think most of my bugs caused by commas are similar to the one shown by the OP. This means this is not a common source of bugs: foo(), bar(); While this is sometimes a trap: auto x = foo(), bar(); So maybe it's enough to disallow using the last expression of a comma sequence as result of the whole expression? I don't know. I almost never use commas for such purposes. What are the use case for those commas?
Well here's my two cents. Commas should only be used to separate parameters, and one exception to this is in for and foreach where they have specific purposes. With the way automatic type detection I would say instead remove them entirely. For the few for cases where you need multiple commands, use a block statement instead. for(; c < x.length; c++, othercommands) becomes for(; c < x.length; {c++; othercommands;}) Actually seeing that you know the last block is together within the {}'s. Could also add that for the init part, but not the conditional. Course if it had to return something, then 'return' could be applicable. No return, then it's automatically type void. //TDPL pg 61 int a = 5 int b = 10 int c = (a = b, b = 7, 8); becomes: int c = {a = b; b = 7; 8;}; int c = {a = b; b = 7; return 8;}; int[] x; foreach(i, val; x) //still applicable, but only real case now that i can think of. Like this it looks less like a function call and a scope instead; but still returns something from a scope as it's return value. Although then it's almost a lambda function, except without calling parameters. Mmm thoughts?
Apr 27 2012
parent "Era Scarecrow" <rtcvb32 yahoo.com> writes:
On Saturday, 28 April 2012 at 03:19:19 UTC, Era Scarecrow wrote:
 becomes:

 int c = {a = b; b = 7; 8;};
 int c = {a = b; b = 7; return 8;};

  Like this it looks less like a function call and a scope 
 instead; but still returns something from a scope as it's 
 return value. Although then it's almost a lambda function, 
 except without calling parameters. Mmm thoughts?
I tend to edit my text all over the place so sorry. The first one {a = b; b = 7; 8;}; was suppose to have a note it would error while assigning value of void return value. Using the blocks/scope makes the book example look less like a function call; But can still return something from a scope as it's return value. Although then it's almost a lambda function except without calling parameters. Most likely it wouldn't return anything, if you needed a return you use a lambda instead. So: a = b; b = 7; int c = 8; //returns void so there is simply no block or int c = (){a = b; b = 7; return 8;};
Apr 27 2012
prev sibling next sibling parent Artur Skawina <art.08.09 gmail.com> writes:
On 04/21/12 14:23, Benjamin Thaut wrote:
 Hi,
 I just had a bug due to the unitentional usage of the comma operator. So I'm
wondering if there could something be done so that the compiler prevents
something like this:
 
 memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof),
InitializeMemoryWith.NOTHING);
 
 This first excutes AllocateMemory, then throws away the result and then casts
the enum InitializeMemory.NOTHING value to a pointer, which will always result
in a null pointer. This took me quite some time to spot.
 What I actually wanted to do:
 
 memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof,
InitializeMemoryWith.NOTHING));
 
 1) So is it actually neccessary that enums can be casted directly to pointers?
 2) Is the functionality provided by the comma operator actually worth the bugs
it causes?
Probably, but it *is* rarely used... However the problem is the allocator, which should also take the type is an argument and do the cast internally. That plus an overload for arrays would avoid these kinds of bugs (since an API like this will be enough for most use cases). And, yes, the D std runtime got this wrong too. (The void*alloc(size_t,flags) versions are useful sometimes, of course) artur
Apr 21 2012
prev sibling next sibling parent Norbert Nemec <Norbert Nemec-online.de> writes:
I fully agree! I wonder why the comma operator made it into D at all. 
This would have been exactly the kind of nasty language details that D 
could have cleaned out.



On 21.04.2012 14:23, Benjamin Thaut wrote:
 Hi,
 I just had a bug due to the unitentional usage of the comma operator. So
 I'm wondering if there could something be done so that the compiler
 prevents something like this:

 memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof),
 InitializeMemoryWith.NOTHING);

 This first excutes AllocateMemory, then throws away the result and then
 casts the enum InitializeMemory.NOTHING value to a pointer, which will
 always result in a null pointer. This took me quite some time to spot.
 What I actually wanted to do:

 memStart = cast(T*)(m_allocator.AllocateMemory(size * T.sizeof,
 InitializeMemoryWith.NOTHING));

 1) So is it actually neccessary that enums can be casted directly to
 pointers?
 2) Is the functionality provided by the comma operator actually worth
 the bugs it causes?

 Kind Regards
 Benjamin Thaut
Apr 27 2012
prev sibling parent reply Manfred Nowak <svv1999 hotmail.com> writes:
Benjamin Thaut wrote:

 I just had a bug due to the unitentional usage of the comma operator.
No language is able to read between the lines. Actually you moved a closing parenthesis over a lexical distance of four token. On this groundadition one can make up similar fruitless remarks. unintentional usage of exponential: | f( 1.0, 1.0e9) but wanted | fe9( 1.0, 1.0) -manfred
Apr 27 2012
parent reply "David Nadlinger" <see klickverbot.at> writes:
On Friday, 27 April 2012 at 21:08:33 UTC, Manfred Nowak wrote:
 unintentional usage of exponential:
 |  f( 1.0, 1.0e9)
 but wanted
 |  fe9( 1.0, 1.0)
I wait for the post where you admit that you made _that_ mistake in code as well. Sorry, but I think your own remark is quite a bit more fruitless than the one you were commenting on… David
Apr 27 2012
parent reply Manfred Nowak <svv1999 hotmail.com> writes:
David Nadlinger wrote:

 quite a bit more fruitless than the one you were commenting on
May be. But then a definition of fruitfullness is missing. Walter once changed the language because a change of a "." to a "," or vice versa might change an actual parameter list from | (1,2.3) to | (1,2,3) That is a distance of zero for characters and token. The problem presented here shows distances of about twenty characters or four token. Does fruitfullness reach up to hundred characters or ten tokens? Please specify the upper bound. -manfred
Apr 27 2012
parent reply "David Nadlinger" <see klickverbot.at> writes:
On Saturday, 28 April 2012 at 06:44:08 UTC, Manfred Nowak wrote:
 Does fruitfullness reach up to hundred characters or ten tokens?
The point I was hinting at is that abstract lexical distance isn't necessarily a valid metric for how similar two snippets of code appear to be, resp. how easy it is to make hard-to-find mistakes in a hurry. On a related note – and please do not take this as a personal attack, but rather as a suggestion how your participation in online discussions might become more, uhm, fruitful – I sometimes wonder if you deliberately try _not_ to understand other people. Communicating, let alone doing so efficiently, doesn't work that way. David
Apr 28 2012
parent Manfred Nowak <svv1999 hotmail.com> writes:
David Nadlinger wrote:

 how similar [...]
 how easy [...]
 Communicating [...] doesn't work that way.
If someone has a usable definition on how to communicate or find similarities _easily_ then please show up. Such a definition is the start for splitting them into possibly intended software clones and unintended but syntactically correct mishaps. -manfred
Apr 28 2012