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?