Path: ...!3.eu.feeder.erje.net!feeder.erje.net!weretis.net!feeder8.news.weretis.net!eternal-september.org!feeder3.eternal-september.org!news.eternal-september.org!.POSTED!not-for-mail From: David Brown Newsgroups: comp.lang.c Subject: Re: Recursion, Yo Date: Wed, 10 Apr 2024 16:46:43 +0200 Organization: A noiseless patient Spider Lines: 109 Message-ID: References: <87edbestmg.fsf@bsb.me.uk> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit Injection-Date: Wed, 10 Apr 2024 14:46:45 +0200 (CEST) Injection-Info: dont-email.me; posting-host="7a89ab18d1e4b124320c42cc3e6d2a2d"; logging-data="1081600"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX18EpPUHPh4JVI4Q/kJSUqV9Es9SmUTR3yQ=" User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.11.0 Cancel-Lock: sha1:6u7x5THfQt9gAuQMwWgRn0U19Pw= Content-Language: en-GB In-Reply-To: Bytes: 5590 On 10/04/2024 14:42, bart wrote: > On 10/04/2024 10:18, David Brown wrote: >> On 10/04/2024 09:52, Lawrence D'Oliveiro wrote: >>> On Wed, 10 Apr 2024 09:11:49 +0200, David Brown wrote: >>> >>>> It is not much used in practice, AFAIK.  For some cases the code >>>> generation for nested functions was fine and straight-forward.  In >>>> other >>>> cases, however, it required a trampoline generated on the stack, and >>>> that became a real pain once non-executable stacks came into fashion. >>> >>> That would be true of those other languages that require the feature, >>> too. >>> >> >> There may be other differences in the languages that reduce that >> effect - or it could be a problem there too.  I don't know the >> details. (Perhaps those on an Ada newsgroup would know better.) >> >> The problem with trampolines comes about when you want to take the >> address of the nested function and use that outside of the surrounding >> function, while you also have variables captured by reference. >> >>>> Nested functions were never as interesting for C++ as you already have >>>> better mechanisms for controlling scope and data access - classes and >>>> their methods, including nested classes. >>> >>> Python does both. Just because you have classes doesn’t mean functions >>> can’t be first-class objects, too. >> >> True.  But Python is a very different language from C++.  In Python, >> not only are functions objects in themselves, but so are classes (the >> definition of the classes, rather than just instances).  Python is a >> lot more "meta" than C++. >> >> Basically, anything you could do with a nested function in gcc C you >> can do in C++: >> >> int sum_square(int x, int y) { >>      int square(z) {               // int z ?? >>          return z * z; >>      } >>      return square(x) + square(y); >> } > > That's not an interesting use of a local function! You can move square() > outside, and it would still work, putting aside any clashes with > existing names called 'square'. Sure. It was not intended to be anything other than a very simple nested function written in gcc C extension syntax, and the same thing written in standard C++, to demonstrate how you can write nested functions in C++ without this extension. Local functions without capturing local data are perhaps not interesting, but they can be neat from the viewpoint of limiting the scope of identifiers. > > The challenges of local functions are to do with accessing transient > variables belonging to their enclosing function. Yes. And you can do that with the gcc extension, and also with C++ lambdas. > Especially when a > reference to the local function is called from outside the lexical scope > of the enclosing function, with extra difficulties when the enclosing > function is no longer active. > These are the kinds of situations where the gcc extension needs to use trampolines. C++ lambdas are closures, and can hold more information - each lambda is its own type, and the size of that type can be different for different lambdas (it can include pointers to the variables captured by reference, for example). This makes lambdas much easier, safer and more efficient to use within a translation unit - but makes them a bit more fiddly if they capture local variables and you need to pass them to something defined outside the current TU. (You can't use any local function outside the scope of the enclosing code if the local function has reference captures - that applies to all types of local functions.) > > >> int sum_square(int x, int y) { >>      auto square = [](int z) { >>          return z * z; >>      } >>      return square(x) + square(y); >> } > > What's the significance of the '[]' here? > It's the syntax for a C++ lambda. You can put captures in there, or leave it empty for no captures. Just for your entertainment, with C++ lambdas this is now legal code: void foo(void) { [](){}(); } (It defines a lambda with no captures and no parameters, that does nothing, then it invokes it.)