Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c++
Subject: Re: two's complement idea
Date: Sat, 15 Feb 2020 06:44:38 -0800
Organization: A noiseless patient Spider
Lines: 112
Message-ID: <865zg7hpux.fsf@linuxsc.com>
References: <4hBWF.107660$LY2.60603@fx23.am4> <20200125134202.8939b7b4f1db1e1f59c1411d@cvine--nospam--.freeserve.co.uk> <86r1zlgpyx.fsf@linuxsc.com>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="9b44be6d216a534b4907eb1c17f8f0ca"; logging-data="26149"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1/aJsDUbK3VK/HBXcGTToyiPXFomEuwOUw="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:gXcd2BmO0WZvwFHT/B4scnKgL3Q= sha1:JdYesS0CuZqZlUNqarM/AO2IwA4=
Xref: csiph.com comp.lang.c++:71858
Paavo Helde writes:
> On 27.01.2020 12:20, Tim Rentsch wrote:
>
>> Paavo Helde writes:
>>
>>> On 25.01.2020 16:58, Bart wrote:
>>>
>>>> How would C++ help here, to avoid either that extra logic, or the use of
>>>> that goto? Here's the current outline (for_each_pwq is a macro expanding
>>>> to a regular for-header):
>>>>
>>>> L:
>>>> A;
>>>> for (...) {
>>>> B;
>>>> if (C) continue;
>>>> D;
>>>> goto L;
>>>> }
>>>
>>> This is an example of some pretty convoluted logic, not even because
>>> of 'goto', but rather because of multiple code execution paths (two
>>> non-default exit paths from inner loop body and no normal exit
>>> path). I would rewrite this along the lines:
>>>
>>> bool foobar(...) {
>>> for (...) {
>>> B;
>>> if (!C) {
>>> D;
>>> return false;
>>> }
>>> }
>>> return true;
>>> }
>>>
>>> while (true) {
>>> A;
>>> if (foobar(...)) {
>>> break;
>>> }
>>> }
>>
>> To me this alternative is worse than the original. Just a
>> personal reaction.
>
> Yes, must be personal...
I meant only that I am representing only my own viewpoint.
Did you think I meant something else?
>> To give the peanut gallery something to hoot
>> about, and fya, the code (in C++!) may be recast as follows:
>>
>> void
>> funky(){
>> A;
>> for (...) {
>> B;
>> if (C) continue;
>> D;
>> return funky();
>> }
>> }
>
> With the original example, this rewrite would be valid in C where 'A;'
> contained mutex locking and 'D;' contained mutex unlocking code.
Yes, I was talking about such cases.
> However, in C++ where the lock would be presumable implemented as an
> RAII class, the recursive call would not work any more. The mutex
> might not support recursive locking, and even if it does, the
> recursive call would call first part of A ('flush_workqueue(wq);')
> under the mutex lock, which would be all wrong I suspect.
Right. When there is behavior resulting from destructor calls, trying
to use (what looks like) a recursive tail call is very likely a bad
idea even if it isn't outright wrong, which it certainly could be.
> So, is this a case where using a 'goto' would be in some sense more
> justified in C++ than in C?
I think I would say using a 'goto' is more likely to be justifiable
in cases like this one (that is, more likely in C++ than in C). It
may be that there are other ways of coding the needed functionality
that do not use a 'goto'. But considering that pending destructor
behavior can eliminate this one alternative, it looks like C has an
option available that C++ does not, at least not in practical terms.
And that could result in using a 'goto' being the most attractive
alternative available in C++ but not in C.
> BTW, in my own code I have several times encountered similar awkward
> "backward goto" scenarios needed only for unlocking a mutex. And the
> result has always been a mess I'm afraid.
That's interesting. Is that always because of pending destructor
behavior? If it is, that suggests that the RAII pattern using
standard constructor/destructor semantics has some shortcomings,
which may indicate a need for other behavior choices. For example,
the funky() function above could be writeable using a new 'creturn'
construct, written as
creturn funky();
where 'creturn' means first run any pending destructors, and only
after they finish execute the (implied) return statement. Doing
that avoids all the nested locking problems, and also makes the
apparent "tail call" be a true tail call, and so could be optimized
to reuse the stack frame. What other kinds of constructs might make
your troublesome mutex uses more tractable?