July 01, 2016
On 7/1/16 3:43 PM, Patrick Schluter wrote:
> On Friday, 1 July 2016 at 16:30:41 UTC, Andrei Alexandrescu wrote:
>> https://issues.dlang.org/show_bug.cgi?id=16224 -- Andrei
>
> That
>
>     do {
>     } while(0)
>
> construct is ridiculous. It's cargo cult at its worst.

That escalated quickly. -- Andrei


July 01, 2016
On Friday, 1 July 2016 at 19:43:05 UTC, Patrick Schluter wrote:
> It looks like a loop, but isn't one.
> It doesn't look like a goto, but is one.

Yes, it looks buggy, and the -cov did the right thing by marking it as uncovered as this could be a serious and difficult to find bug.

I wonder why people write such ugly and misleading code deliberately? The compiler turns it into jumps anyway and in this case a bool or gotos are much more readable and not slower.

In fact, a statemachine implemented as gotos can be very clean, efficient and easy to debug. It's a matter of structuring the code layout.


July 01, 2016
On 7/1/16 4:08 PM, Andrei Alexandrescu wrote:
> On 7/1/16 2:46 PM, Steven Schveighoffer wrote:
>> On 7/1/16 2:15 PM, Andrei Alexandrescu wrote:
>>> On 7/1/16 2:05 PM, Chris wrote:
>>>> On Friday, 1 July 2016 at 16:30:41 UTC, Andrei Alexandrescu wrote:
>>>>> https://issues.dlang.org/show_bug.cgi?id=16224 -- Andrei
>>>>
>>>> I fail to see why it should not mark it as uncovered in the `cube`
>>>> example. After all the statement is never covered, because `do`
>>>> executes
>>>> before the condition in `while` is checked. Unless you mean it
>>>> should be
>>>> optimized away by the compiler, which in turn has nothing to do with
>>>> -cov.
>>>
>>> Yah it's a bit subtle. That line is in fact pure punctuation, so even
>>> though there's no flow through it that's totally fine (as much as you
>>> wouldn't expect a line with a "}" to show no coverage). -- Andrei
>>
>> Suppose one wants to check if you've covered all cases inside the while
>> loop (with breaks or returns). Then, one would WANT to see 0 coverage
>> there (non-zero coverage would mean an error in logic).
>>
>> To remove that feedback would mess up someone else's use case.
>
> This argument is phony. Unconvinced. -- Andrei

I don't use while(0), so I have to invent a hypothetical use case. It's not phony. I could just as easily say that your coding style is illegitimate, and you should use while(true) instead (and thereby get 100% coverage analysis). But I'm not saying that.

There is a legitimate difference between breaking out of the while loop using breaks, and breaking out using the while(0) condition. Why do you want coverage analysis to ignore that difference? Why would someone else's use case that relies on executing or not executing while(0) be invalid?

-Steve
July 02, 2016
On Friday, 1 July 2016 at 20:09:30 UTC, Andrei Alexandrescu wrote:
> On 7/1/16 3:43 PM, Patrick Schluter wrote:
>> On Friday, 1 July 2016 at 16:30:41 UTC, Andrei Alexandrescu wrote:
>>> https://issues.dlang.org/show_bug.cgi?id=16224 -- Andrei
>>
>> That
>>
>>     do {
>>     } while(0)
>>
>> construct is ridiculous. It's cargo cult at its worst.
>
> That escalated quickly. -- Andrei

Nothing personal. As I said in the initial message, I had to put up with that construct for the last 15 years because my colleague loves it. So I had ample time to learn to hate it with a passion.
July 02, 2016
On Friday, 1 July 2016 at 20:30:30 UTC, Steven Schveighoffer wrote:
> On 7/1/16 4:08 PM, Andrei Alexandrescu wrote:
>> On 7/1/16 2:46 PM, Steven Schveighoffer wrote:
>>> On 7/1/16 2:15 PM, Andrei Alexandrescu wrote:
>>>> On 7/1/16 2:05 PM, Chris wrote:
>>>>> On Friday, 1 July 2016 at 16:30:41 UTC, Andrei Alexandrescu wrote:
>>>>>> https://issues.dlang.org/show_bug.cgi?id=16224 -- Andrei
>>>>>
>>>>> I fail to see why it should not mark it as uncovered in the `cube`
>>>>> example. After all the statement is never covered, because `do`
>>>>> executes
>>>>> before the condition in `while` is checked. Unless you mean it
>>>>> should be
>>>>> optimized away by the compiler, which in turn has nothing to do with
>>>>> -cov.
>>>>
>>>> Yah it's a bit subtle. That line is in fact pure punctuation, so even
>>>> though there's no flow through it that's totally fine (as much as you
>>>> wouldn't expect a line with a "}" to show no coverage). -- Andrei
>>>
>>> Suppose one wants to check if you've covered all cases inside the while
>>> loop (with breaks or returns). Then, one would WANT to see 0 coverage
>>> there (non-zero coverage would mean an error in logic).
>>>
>>> To remove that feedback would mess up someone else's use case.
>>
>> This argument is phony. Unconvinced. -- Andrei
>
> I don't use while(0), so I have to invent a hypothetical use case. It's not phony. I could just as easily say that your coding style is illegitimate, and you should use while(true) instead (and thereby get 100% coverage analysis). But I'm not saying that.
>
> There is a legitimate difference between breaking out of the while loop using breaks, and breaking out using the while(0) condition. Why do you want coverage analysis to ignore that difference? Why would someone else's use case that relies on executing or not executing while(0) be invalid?
>
> -Steve

The do {} while(0) "trick" is generally used in C as a poor mans scope(exit) construct without using goto. It is to have one point where the resources used by a function can be freed without duplicating the code everywhere, especially if the function has multiple return points. So in practice it is only "useful" on complex functions with acquisition of resources (memory, files etc) and several exit points (error variants). These kind of functions already have difficult execution flows and adding a level of obfuscation on top of it is not the right solution. Using a goto, while not being the best solution, has at least the merrit of providing a searchable and meaningfull label (goto error or goto finally or goto cleanup are obvious, break not so much) to find the exit. With break it's a little bit more difficult. Add loops and switch's to the equation and you're in for a very confusing debugging session.

July 02, 2016
On Saturday, 2 July 2016 at 06:45:37 UTC, Patrick Schluter wrote:
> On Friday, 1 July 2016 at 20:09:30 UTC, Andrei Alexandrescu wrote:
>> On 7/1/16 3:43 PM, Patrick Schluter wrote:
>>> On Friday, 1 July 2016 at 16:30:41 UTC, Andrei Alexandrescu wrote:
>>>> https://issues.dlang.org/show_bug.cgi?id=16224 -- Andrei
>>>
>>> That
>>>
>>>     do {
>>>     } while(0)
>>>
>>> construct is ridiculous. It's cargo cult at its worst.
>>
>> That escalated quickly. -- Andrei
>
> Nothing personal.

I should detail, nothing personal against you, but very personal on my side :-)
July 02, 2016
On 07/01/2016 07:30 PM, Andrei Alexandrescu wrote:
> https://issues.dlang.org/show_bug.cgi?id=16224 -- Andrei

Works as it should, nothing to fix.
July 02, 2016
On Friday, 1 July 2016 at 20:08:30 UTC, Andrei Alexandrescu wrote:
>> To remove that feedback would mess up someone else's use case.
>
> This argument is phony. Unconvinced. -- Andrei

If you are hellbent on using a loop to execute a scope once, do something that makes it clear at the top of the scope:

for once {
   ...
}

e.g.:

import std.stdio;

void main(){

	foreach(_;[1]){
		writeln("once");
	}
	
}

July 02, 2016
On Friday, 1 July 2016 at 20:06:39 UTC, Andrei Alexandrescu wrote:

> What is the condition? -- Andrei

`while`'s job is it to test for a condition and loop while the condition is true, even if the condition is `true` or `0`. So -cov does the right thing. It checks whether this part of the loop (`while xyz is the case`) is executed. In your case it isn't which is _your_ problem and not -cov's. It actually shows that your code might not be optimal, if you have something in it that is never executed and can never be covered. A dead statement.
July 02, 2016
On Saturday, 2 July 2016 at 07:04:28 UTC, Patrick Schluter wrote:
> On Friday, 1 July 2016 at 20:30:30 UTC, Steven Schveighoffer wrote:
>> On 7/1/16 4:08 PM, Andrei Alexandrescu wrote:
>>> On 7/1/16 2:46 PM, Steven Schveighoffer wrote:
>>>> On 7/1/16 2:15 PM, Andrei Alexandrescu wrote:
>>>>> On 7/1/16 2:05 PM, Chris wrote:
>>>>>> On Friday, 1 July 2016 at 16:30:41 UTC, Andrei Alexandrescu wrote:
>>>>>>> https://issues.dlang.org/show_bug.cgi?id=16224 -- Andrei
>>>>>>
>>>>>> I fail to see why it should not mark it as uncovered in the `cube`
>>>>>> example. After all the statement is never covered, because `do`
>>>>>> executes
>>>>>> before the condition in `while` is checked. Unless you mean it
>>>>>> should be
>>>>>> optimized away by the compiler, which in turn has nothing to do with
>>>>>> -cov.
>>>>>
>>>>> Yah it's a bit subtle. That line is in fact pure punctuation, so even
>>>>> though there's no flow through it that's totally fine (as much as you
>>>>> wouldn't expect a line with a "}" to show no coverage). -- Andrei
>>>>
>>>> Suppose one wants to check if you've covered all cases inside the while
>>>> loop (with breaks or returns). Then, one would WANT to see 0 coverage
>>>> there (non-zero coverage would mean an error in logic).
>>>>
>>>> To remove that feedback would mess up someone else's use case.
>>>
>>> This argument is phony. Unconvinced. -- Andrei
>>
>> I don't use while(0), so I have to invent a hypothetical use case. It's not phony. I could just as easily say that your coding style is illegitimate, and you should use while(true) instead (and thereby get 100% coverage analysis). But I'm not saying that.
>>
>> There is a legitimate difference between breaking out of the while loop using breaks, and breaking out using the while(0) condition. Why do you want coverage analysis to ignore that difference? Why would someone else's use case that relies on executing or not executing while(0) be invalid?
>>
>> -Steve
>
> The do {} while(0) "trick" is generally used in C as a poor mans scope(exit) construct without using goto. It is to have one point where the resources used by a function can be freed without duplicating the code everywhere, especially if the function has multiple return points. So in practice it is only "useful" on complex functions with acquisition of resources (memory, files etc) and several exit points (error variants). These kind of functions already have difficult execution flows and adding a level of obfuscation on top of it is not the right solution. Using a goto, while not being the best solution, has at least the merrit of providing a searchable and meaningfull label (goto error or goto finally or goto cleanup are obvious, break not so much) to find the exit. With break it's a little bit more difficult. Add loops and switch's to the equation and you're in for a very confusing debugging session.

Sorry for answering my own comments but the do while(0) code at the link is already a good example of why that construct is bad. To discover what it does, one has to try every possible way in its head, see that it uses an inverted logic (i.e. a double negation) if my parameter isn't a specific value don't do what is close by.

    do
    {
        if (x != 0)
            break;
        if (x != 1)
            break;
        if (x != -1)
            break;
        return x;
    }
    while (0);
    return x * x * x;

is really a lot of lines to write

    if (x == 0 || x == 1 || x == -1)
        return x*x*x;
    else
        return x;

or

    return (x == 0 || x == 1 || x == -1) ? x*x*x : x;


Sorry to still insist on that side show, but it is this inverted logic that is worst part of this construct, making it really, really difficult to analyze in practice.