C++ Logo

std-proposals

Advanced search

Re: [std-proposals] escaping nested scopes : __escape

From: Sebastian Wittmeier <wittmeier_at_[hidden]>
Date: Mon, 1 May 2023 16:10:21 +0200
You can use a lambda at the appropriate position instead.   [&] {     for (int i = 0; i < x: i++) {         for (int j = 0; j < y; j++) {             for (int k = 0; k < z; k++) {                 if (something)                     return;             }        }    } }();   -----Ursprüngliche Nachricht----- Von:Frederick Virchanza Gotham via Std-Proposals <std-proposals_at_[hidden]> Gesendet:Mo 01.05.2023 15:53 Betreff:[std-proposals] escaping nested scopes : __escape An:std-proposals <std-proposals_at_[hidden]>; CC:Frederick Virchanza Gotham <cauldwell.thomas_at_[hidden]>; When it comes to breaking out of nested loops, some programmers use the 'goto' keyword , but nowadays I think the following strategy is more prevalent:    bool mega_break = false;    for ( unsigned i = 0u; i < x; ++i )    {        for ( unsigned j = 0u; j < y; ++j )        {            for ( unsigned k = 0u; k < z; ++k )            {                if ( something )                {                    mega_break = true;                    break;                }            }            if (mega_break) break;        }        if (mega_break) break;    } Over the years I've seen a few different proposals for how to deal with breaking out of nested loops. The proposals I've read over the years have had stuff like the following:        break 3;  // break out of this loop, then break out of outer, then again break out of outer and also:        continue 3;  // break out of this loop, then break out of the outer, then continue the outer I don't think I've ever seen a proposal though that deals in scopes rather than loops. Take the following code for example:    void Func(void)    {        {            lock_guard mylock(my_mutex);            some_global_object.DoSomething();            {                lock_guard mylock2(my_other_mutex);                some_other_global_object.DoAnotherThing();                {                    lock_guard mylock3(alien_mutex);                    alien_object.KickWatchdog();                }                some_other_global_object.ReportWatchdogKicked():            }            some_global_object.DoTheSecondThing();        }        // Do some other important stuff    } In the above code we have nested scopes but no loops. If we had an '__escape' keyword we could escape out of the nested scopes (and appropriately call destructors when doing so -- thereby unlocking the mutexes in the above example). The syntax could be as follows:        __escape( [number] , [nothing / continue / break] ); 1st operand    :    positive integer >= 1 (must be an integer literal) 2nd operand    :    one of 3 possibilities : 'nothing' / 'continue' / 'break' If the 2nd operand is omitted then the default is 'nothing'. So let's say you want to escape out of 5 scopes, you would do:        __escape(5); Note that the following code is ill-formed:    int constexpr monkey = 2;    __escape( monkey ); The 1st operand must be an integer literal -- not merely a compile time constant, so the compiler shall terminate compilation and issue a diagnostic. If you want to escape out of 3 scopes, you do:        __escape(3); The above is equivalent to:        __escape(3, nothing); The word 'nothing' here indicates that once you've escaped back three scopes, you do nothing. The alternative is to 'continue' or to 'break'. Let's say that you want to escape out of 4 scopes, and then once you find yourself four scopes back in the code, you want to 'continue' the loop:        __escape(4, continue); Or you want to escape out of 3 scopes, and then once you find yourself three scopes back in the code, you want to break out of the loop (or break out of the switch statement):        __escape(3, break); Furthermore, for the sake of debugging and avoiding adding bugs to code, there could be a third operand to the __escape operator. The third operand is the count of how many scopes you expect there to be from the beginning of the function to where the __escape operator is encountered. So if you were expecting 5 scopes, you would write:        __escape(3, break, 5); This third operand would be useful where you have a very big, very complicated function with many nested loops and nested scopes. If you have a function that's over 150 lines long, and you've to scroll up and down to the top and bottom of it, then if you make a change to the top of the function and then select all of the below code in the text editor and reduce the indentation by one level, you could change the count of scopes. This in particular could happen if more than one person is working on the same code. So let's say you were expecting 5 scopes from where the function began to where the __escape operator was encountered, but now after the function has been altered by a colleague of yours, there are 4 scopes instead of 5. Well, when the compiler encounters the '__escape(3,break,5)' statement, it shall terminate compilation and issue a diagnostic to say that the expected number of scopes is wrong. This would drastically reduce the possibility of introducing a bug. -- Std-Proposals mailing list Std-Proposals_at_[hidden] https://lists.isocpp.org/mailman/listinfo.cgi/std-proposals

Received on 2023-05-01 14:10:24