[HN Gopher] The Cost of a Closure in C
       ___________________________________________________________________
        
       The Cost of a Closure in C
        
       Author : ingve
       Score  : 182 points
       Date   : 2025-12-11 07:21 UTC (15 hours ago)
        
 (HTM) web link (thephd.dev)
 (TXT) w3m dump (thephd.dev)
        
       | ddtaylor wrote:
       | I actually enjoy trampoline functions in C a bit and it's one of
       | the GNU extensions I use sometimes.
        
       | RossBencina wrote:
       | Good to see Borland's __closure extension got a mention.
       | 
       | Something I've been thinking about lately is having a "state"
       | keyword for declaring variables in a "stateful" function. This
       | works just like "static" except instead of having a single global
       | instance of each variable the variables are added to an
       | automatically defined struct, whose type is available using
       | "statetype(foo)" or some other mechanism, then you can invoke foo
       | as with an instance of the state (in C this would be an explicit
       | first parameter also marked with the "state" parameter.) Stateful
       | functions are colored in the sense that if you invoke a nested
       | stateful function its state gets added to the caller's state.
       | This probably won't fly with separate compilation though.
        
         | juvoly wrote:
         | That sounds cool, but this quickly gets complicated. Some
         | aspects that need to be addressed:
         | 
         | - where does the automatically defined struct live? Data
         | segment might work for static, but doesn't allow dynamic use.
         | Stack will be garbage if closure outlives function context (ie.
         | callback, future). Heap might work, but how do you prevent
         | leaks without C++/Rust RAII?
         | 
         | - while a function pointer may be copied or moved, the state
         | area probably cannot. It may contain pointers to stack object
         | or point into itself (think Rust's pinning)
         | 
         | - you already mention recursion, compilation
         | 
         | - ...
        
           | fuhsnn wrote:
           | IMO the C way is to allow users to explicitly manage context
           | area, along the lines of posix ucontext.h or how the author's
           | closure proposal handle closure allocation[1]. [1] https://th
           | ephd.dev/_vendor/future_cxx/papers/C%20-%20Functio...
        
         | vintagedave wrote:
         | Yes, though it was a remarkably brief mention. I believe
         | Borland tried to standardise it back in 2002 or so,* along with
         | properties. (I was the C++Builder PM, but a decade and a half
         | after that attempt.)
         | 
         | C++Builder's entire UI system is built around __closure and it
         | is remarkably efficient: effectively, a very neat fat pointer
         | of object instance and method.
         | 
         | [*] Edit: two dates on the paper, but "bound pointer to member"
         | and they note the connection to events too: https://www.open-
         | std.org/jtc1/sc22/wg21/docs/papers/2002/n13...
        
         | fuhsnn wrote:
         | I dreamed up a similar idea[1] upon reading the author's
         | closure proposal, it's also really close to async coroutines.
         | 
         | [1]
         | https://github.com/ThePhD/future_cxx/issues/55#issuecomment-...
        
         | 1f60c wrote:
         | > a "state" keyword for declaring variables in a "stateful"
         | function
         | 
         | Raku (nee Perl 6) has this!
         | https://docs.raku.org/language/variables#The_state_declarato...
        
       | mgaunard wrote:
       | I feel the results say more about the testing methodology and
       | inlining settings than anything else.
       | 
       | Practically speaking all lambda options except for the one
       | involving allocation (why would you even do that) are equivalent
       | modulo inlining.
       | 
       | In particular, the caveat with the type erasure/helper variants
       | is precisely that it prevents inlining, but given everything is
       | in the same translation unit and isn't runtime-driven, it's still
       | possible for the compiler to devirtualize.
       | 
       | I think it would be more interesting to make measurements when
       | controlling explicitly whether inlining happens or the function
       | type can be deduced statically.
        
         | gpderetta wrote:
         | Given a Sufficiently Good(tm) compiler, yes, after
         | devirtualization and heap elision all variants should generate
         | exactly the same code. In practice is more complicated.
         | Devirtualization needs to runs after (potentially
         | interprocedural) constant propagation, which might be too late
         | to take advantage of other optimization opportunities, unless
         | the compiler keeps rerunning the optimization pipeline.
         | 
         | In a simple test I see that GCC14 has no problems completely
         | removing the overhead of std::function_ref, but plain
         | std::function is a huge mess.
         | 
         | Eventually we will get there [1], but in the meantime I prefer
         | not to rely on devirtualization, and heap elision is more of a
         | party trick.
         | 
         | edit: to compare early vs late inlining: while gcc 14 can
         | remove one layer of function_ref, it seems that it cannot
         | remove two layers, as apparently doesn't rerun the required
         | passes to take advantage of the new opportunity. It has no
         | problem of course removing an arbitrary large (but finite)
         | layers of plain lambdas.
         | 
         | edit2: GCC15 can remove trivial uses of std::function, but this
         | is very fragile. It still can't remove two function_ref.
         | 
         | [1] for example 25 years ago compilers were terrible at
         | removing abstraction overhead of the STL, today there is very
         | little cost.
        
           | mgaunard wrote:
           | You can just write the benchmark in such a way that the
           | optimizations are not possible.
        
       | capestart wrote:
       | The breakdown of lambda, blocks, and nested functions
       | demonstrates how important implementation and ABI details are in
       | addition to syntax. I think the standard for C should include a
       | straightforward, first class wide function pointer along with a
       | closure story to stop people from adding these half portable,
       | half spooky extensions.
        
         | uecker wrote:
         | This.
        
       | Progge wrote:
       | Long time ago I wrote C. Could anyone fill me in why the first
       | code snippet is arg parsing the way it is?
       | 
       | int main(int argc, char* argv[]) {                 if (argc > 1)
       | {              char\* r_loc = strchr(argv[1], 'r');
       | if (r_loc != NULL) {                ptrdiff_t r_from_start =
       | (r_loc - argv[1]);                if (r_from_start == 1 &&
       | argv[1][0] == '-' && strlen(r_loc) == 1) {             in_reverse
       | = 1;           }               }            }            ...
       | 
       | }
       | 
       | Why not
       | 
       | if (argc > 1 && strcmp(argv[1], "-r") == 0) {
       | in_reverse = 1;
       | 
       | }
       | 
       | for example?
        
         | tapete2 wrote:
         | It doesn't even make sense to use strchr for determining the
         | position of 'r', when the code checks that the position of '-'
         | is at index 0.
         | 
         | Your solution is perfectly fine. Even if you don't have access
         | to strchr for some reason, the original snippet is really
         | convoluted.
         | 
         | You could just write (strlen(argv[1]) > 1 && argv[1][0] == '-'
         | && argv[1][0] == 'r') if you really want to.
        
           | microtherion wrote:
           | It could make _some_ sense to use strchr, because in
           | idiomatic UNIX tools, single character command line options
           | can be clustered. But that also means that subsequent code
           | should not be tested for a specific position.
           | 
           | And if you ever find yourself actually doing command line
           | parsing, use getopt(). It handles all the corner cases
           | reliably, and consistent with other tools.
        
           | unwind wrote:
           | Of course, `&&` in C is short-circuiting so it's safe without
           | the `strlen()` too, as long as the argument is there i.e. not
           | NULL.
           | 
           | Also, the use of a convoluted `if` to conditionally assign a
           | literal boolean is a code smell (to me), I would drop the
           | `if` and just use:                   in_reverse = argc > 0 &&
           | argv[1][0] == '-' && argv[1][1] == 'r';
           | 
           | if a more forward-thinking/strict check is not needed.
        
         | Joker_vD wrote:
         | I suspect it was adopted from a bigger snippet that had support
         | for parsing things like "-abc" as "-a -b -c", etc.
        
         | CerryuDu wrote:
         | Not to mention the potential signed integer overflow in (*right
         | - *left) and (*left - *right), which is undefined behavior. And
         | even if you rely on common two's complement wraparound, the
         | result may be wrong; for example, (INT_MAX-(-1)) should
         | mathematically yield a positive value, but the function will
         | produce INT_MIN, which is negative.
         | 
         | And then we have this "modern" way of spelling pointers, "const
         | int* right" (note the space). In C, declaration syntax mirrors
         | use, so it should be "const int *right", because "*right" is a
         | "const int".
         | 
         | I feel too old for this shit. :(
        
           | Joker_vD wrote:
           | const int left = *(const int*)untyped_left, right = *(const
           | int*)untyped_right;              return in_reverse?
           | (right > left) - (right < left)           : (left > right) -
           | (left < right);
           | 
           | I wonder if there is a way to actually do it with only
           | arithmetic, without comparisons?
        
       | nesarkvechnep wrote:
       | I'm thinking of using C++ for a personal project specifically for
       | the lambdas and RAII.
       | 
       | I have a case where I need to create a static templated lambda to
       | be passed to C as a pointer. Such thing is impossible in Rust,
       | which I considered at first.
        
         | pornel wrote:
         | Yeah, Rust closures that capture data are fat pointers { fn*,
         | data* }, so you need an awkward dance to make them thin
         | pointers for C.                   let mut state = 1;
         | let mut fat_closure = || state += 1;         let (fnptr,
         | userdata) = make_trampoline(&mut &mut fat_closure);
         | unsafe {             fnptr(userdata);         }
         | assert_eq!(state, 2);              use std::ffi::c_void;
         | fn make_trampoline<C: FnMut()>(closure: &mut &mut C) -> (unsafe
         | fn(*mut c_void), *mut c_void) {             let fnptr =
         | |userdata: *mut c_void| {                 let closure: *mut
         | &mut C = userdata.cast();                 (unsafe { &mut
         | *closure })()             };             (fnptr, closure as
         | *mut _ as *mut c_void)         }
         | 
         | It requires a userdata arg for the C function, since there's no
         | allocation or executable-stack magic to give a unique function
         | pointer to each data instance. OTOH it's zero-cost. The generic
         | make_trampoline inlines code of the closure, so there's no
         | extra indirection.
        
           | nesarkvechnep wrote:
           | I know about this technique but it uses too much unsafe for
           | my taste. Not that it's bad or anything, just a personal
           | preference.
        
           | skavi wrote:
           | > Rust closures that capture data are fat pointers { fn _,
           | data_ }
           | 
           | This isn't fully accurate. In your example, `&mut C` actually
           | has the same layout as usize. It's not a fat pointer. `C` is
           | a concrete type and essentially just an anonymous struct with
           | FnMut implemented for it.
           | 
           | You're probably thinking of `&mut dyn FnMut` which is a fat
           | pointer that pairs a pointer to the data with a pointer to a
           | VTable.
           | 
           | So in your specific example, the double indirection is
           | unnecessary.
           | 
           | The following passes miri: https://play.rust-
           | lang.org/?version=nightly&mode=debug&editi...
           | 
           | (did this on mobile, so please excuse any messiness).
        
         | queuebert wrote:
         | In Rust, could you instead use a templated struct wrapping a
         | function pointer along with #[repr(C)]?
        
       | sirwhinesalot wrote:
       | I think local functions (like the GNU extension) that behave like
       | C++ byref(&) capturing lambdas makes the most sense for C.
       | 
       | You can call the local functions directly and get the benefits of
       | the specialized code.
       | 
       | There's no way to spell out this function's type, and no way to
       | store it anywhere. This is true of regular functions too!
       | 
       | To pass it around you need to use the type-erased "fat pointer"
       | version.
       | 
       | I don't see how anything else makes sense for C.
        
         | nutjob2 wrote:
         | The price you pay for GCC nested (local) functions is an
         | executable stack with 'trampolines'.
         | 
         | I'm a fan of nested functions but don't think the executable
         | stack hack is worth it, and using a 'display' is a better
         | solution.
         | 
         | See the Dragon Book or Compiler Construction: Principles and
         | Practice (1984) by Louden
        
           | sirwhinesalot wrote:
           | You misunderstood my comment. GNU local function _syntax_ ,
           | C++ [&] lambda _behavior_ (i.e., a hidden struct).
        
             | nutjob2 wrote:
             | I really did, my comment is specific to C.
        
         | gpderetta wrote:
         | > There's no way to spell out this function's type, and no way
         | to store it anywhere. This is true of regular functions too!
         | 
         | well regular functions decay to function pointers. You could
         | have the moral equivalent of std::function_ref (or similarly,
         | borland __closure) in C of course and have closures decay to
         | it.
        
       | Rochus wrote:
       | The benchmark demonstrates that the modern C++ "Lambda" approach
       | (creating a unique struct with fields for captured variables) is
       | effectively a compile-time calculated static link. Because the
       | compiler sees the entire definition, it can flatten the "link"
       | into direct member access, which is why it wins. The performance
       | penalty the author sees in GCC is partly due to the OS/CPU
       | overhead of managing executable stacks, not just code
       | inefficiency. The author correctly identifies that C is missing a
       | primitive that low-level languages perfected decades ago: the
       | bound method (wide) pointer.
       | 
       | The most striking surprise is the magnitude of the gap between
       | std::function and std::function_ref. It turns out std::function
       | (the owning container) forces a "copy-by-value" semantics deeply
       | into the recursion. In the "Man-or-Boy" test, this apparently
       | causes an exponential explosion of copying the closure state at
       | every recursive step. std::function_ref (the non-owning view)
       | avoids this entirely.
        
         | gpderetta wrote:
         | Even if you never copy the std::function the overhead is very
         | large. GCC (14 at least) does not seem to be able to elide the
         | allocation, nor inline the function itself, even if used
         | immediately after use and the object never escapes the
         | function. Given the opportunity, GCC seems to be able to
         | completely remove one layer pf function_ref, but fails at two
         | layers.
        
           | boris wrote:
           | GCC (libstdc++) as all other major C++ runtimes (libc++,
           | MSVC) implements the small object optimization for
           | std::function where a small enough callable is stored
           | directly in std::function's state instead of on the heap.
           | Across these implementations, you can reply on being able to
           | capture two pointers without a dynamic allocation.
        
             | gpderetta wrote:
             | You would think so, but it actually doesn't. last time I
             | checked, libstdc++ could only optimize std::bind closures.
             | A trivial test with a stateless lambda shows this is still
             | the case in GCC14 and 15. In fact I can't even seem to
             | trigger the library optimization with bind.
             | 
             | Differently from GCC14, GCC15 itself does seem to be able
             | to optimize the allocation (and the whole std::function) in
             | trivial cases though (independently of what the library
             | does).
        
           | Rochus wrote:
           | This is exactly right, and the "Man-or-Boy" benchmark hits
           | the worst-case scenario for libstdc++ specifically. The
           | optimization fails here. My "copy-by-value" comment refers to
           | the ownership semantics. Since std::function owns its
           | storage, and the Man-or-Boy recursion passes the closure into
           | the next layer (often by value or by capturing it into a new
           | closure), we trigger the copy constructor. If the SBO limit
           | is exceeded, that copy constructor performs a new heap
           | allocation and a deep copy of the state.
        
       | psyclobe wrote:
       | c++ for the win!! finally!!
        
       | unwind wrote:
       | This was very interesting, and it's obvious from the majority of
       | the text that the author knows a lot about these languages, their
       | implementation, benchmarking corners, and so on. Really!
       | 
       | Therefore it's very jarring with this text after the first C code
       | example:
       | 
       |  _This uses a static variable to have it persist between both the
       | compare function calls that qsort makes and the main call which
       | (potentially) changes its value to be 1 instead of 0_
       | 
       | This feels completely made up, and/or some confusion about things
       | that I would expect an author of a piece like this to really
       | know.
       | 
       | In reality, in _this_ usage (at the global outermost scope level)
       | `static` has nothing to do with persistence. All it does is make
       | the variable  "private" to the translation unit (C parliance,
       | read as "C source code file"). The value will "persist" since the
       | global outermost scope can't go out of scope while the program is
       | running.
       | 
       | It's different when used inside a function, _then_ it makes the
       | value persist between invocations, in practice typically by
       | moving the variable from the stack to the  "global data" which is
       | generally heap-allocated as the program loads. Note that C does
       | not mention the existence of a stack for local variables, but of
       | course that is the typical implementation on modern systems.
        
         | kreco wrote:
         | That's a very weird comment, your spreading your knowledge and
         | not really addresse what could have been changed in the
         | article.
         | 
         | If I follow your comment, you mean that he could have use a
         | non-static global variable instead and avoid mentioning
         | "static" keyword afterward?
        
           | unwind wrote:
           | Oh! Thanks, I was not being as concrete as I imagined. Sorry.
           | 
           | Yes, the `static` can simply be dropped, it does no
           | additional work for a single-file snippet like this.
           | 
           | I tried diving into Compiler Explorer to examine this, and it
           | actually produces slightly different code for the
           | with/without `static` cases, but it was confusing to deeply
           | understand quickly enough to use the output here. Sorry.
        
             | mananaysiempre wrote:
             | I see exactly the same assembly from x86-64 GCC 15.2 with
             | -O2 the first example in the article both as is and without
             | `static`, which makes sense. The two do differ if you add
             | -fPIC, as though you're compiling a dynamic library, and do
             | not add -fvisibility=hidden at the same time, but that's
             | because Linux dynamic linking is badly designed.
        
               | Chabsff wrote:
               | TU-level concepts (mostly) dissolve during the linking
               | stage. You need to compile with -c to generate an object
               | file in order to see the distinction.
               | 
               | Also, the difference manifests in the symbols table, not
               | the assembly.
        
               | mananaysiempre wrote:
               | To clarify, I was talking about Compiler Explorer-cleaned
               | disassembly, same as the comment I was replying to.
        
         | pjmlp wrote:
         | The author contributes to ISO C and ISO C++ working groups, and
         | his latest contribution was #embed.
        
           | steveklabnik wrote:
           | Not just that, the author is the Project Editor for WG14.
           | 
           | This doesn't mean that it's impossible to make mistakes, but
           | still.
        
             | uecker wrote:
             | It means he can edit LaTeX. Of course, JeanHeyd is very
             | qualified, but being project editor for an ISO standard
             | does not require this.
        
               | steveklabnik wrote:
               | I mean, you're closer to the committee than I am, but
               | while that is true in a literal sense, I'd assume that
               | you all would not let someone who knew how to edit LaTeX
               | but not know anything about C hold that position.
        
               | uecker wrote:
               | Assuming we have some choice. Not many people volunteer
               | their time to this work, which is quite a lot and not
               | much fun. Companies also do not invest a lot of resources
               | into C.
        
         | gldrk wrote:
         | >This uses a static variable to have it persist between both
         | the compare function calls that qsort makes and the main call
         | which (potentially) changes its value to be 1 instead of 0
         | 
         | The only misleading thing here is that 'static' is monospaced
         | in the article (this can't be seen on HN). Other than that,
         | 'static variable' can plausibly refer to an object with a
         | static storage duration, which is what the C standard would
         | call it.
         | 
         | >moving the variable from the stack to the "global data" which
         | is generally heap-allocated as the program loads
         | 
         | It is not heap-allocated because you can't free() it. Non-zero
         | static data is not even anonymously mapped, it is file-backed
         | with copy-on-write.
        
         | sfpotter wrote:
         | I had a completely different response reading the sentence.
         | I've been programming in C for 20+ years and am very familiar
         | with exactly the problem the author is discussing. When they
         | referred to a "static variable", I understood immediately that
         | they meant a file static variable private to the translation
         | unit. Didn't feel contrived or made up to me at all; just a
         | reflection of the author's expertise. Precision of language.
        
         | debugnik wrote:
         | It took me a second read to realise that the mention of static
         | is a red herring. I think the author knows that the linkage is
         | irrelevant for the rest of the explanation; it just happens to
         | be static so they called it static. But by drawing attention to
         | it, it does first read like they're confused about the role of
         | static there.
        
         | CerryuDu wrote:
         | I'm finding myself in a weird position now, because I disagree
         | with a whole lot of things in the blog post (well, the parts I
         | was willing to read anyways), but calling that variable static
         | _for_ the sake of persistence _was_ correct.
         | 
         | The fact that you are questioning the use of the term shows
         | that you are not familiar with the ISO C standard. What the
         | author alludes to is _static storage duration_. And whether or
         | not you use the  "static" keyword in that declaration (also
         | definition), the storage duration of the object remains
         | "static". People mostly call those things "global variables",
         | but the proper standardese is "static storage duration". In
         | that sense, the author was right to use "static" for the
         | lifetime of the object.
         | 
         | EDIT: if you drop "static" from that declaration, what changes
         | is the _linkage_ of the identifier (from internal to external).
        
       | keymasta wrote:
       | It's a post about Man or Boy... and the only typo is... the word
       | _son_. Pretty sure it's supposed to be "on"
        
       | trgn wrote:
       | i wish JS gurus understood this before jumping all in on hooks
       | and bloating the runtime footprint of every web app out there
        
       | groundzeros2015 wrote:
       | Thread locals do solve the problem. You create a wrapper around
       | the original function. You set a global thread local user data,
       | you pass in a function which calls the function pointer accepting
       | the user data with the global one.
        
         | srcreigh wrote:
         | Yep. Thread locals are probably faster than the other solutions
         | shown too.
         | 
         | It's confusing to me that thread locals are "not the best idea
         | outside small snippets" meanwhile the top solution is
         | templating on recursion depth with a constexpr limit of 11.
        
           | groundzeros2015 wrote:
           | The method of having static variables to store state in
           | functions is used heavily in ANSI C book. It's honestly a
           | beautiful technique when used prudently.
        
         | gpderetta wrote:
         | reentrancy.
        
           | groundzeros2015 wrote:
           | It doesn't store state for later. It's literally impossible
           | to tell it's happening.
        
       | hyperbolablabla wrote:
       | Stewart Lynch in his 10x VODs mentions his custom Function
       | abstraction in C++. It's super clean and explicit, avoiding
       | `auto` requirement of C++ lambdas. It's use looks something akin
       | to:                   // imagine my_function takes 3 ints, the
       | first 2 args are captured and curried.
       | Function<void(int)> my_closure(&my_function, 1, 2);
       | my_closure(3);
       | 
       | I've never implemented it myself, as I don't use C++ features all
       | too much, but as a pet project I'd like to someday. I wonder how
       | something like that compares!
        
         | spacechild1 wrote:
         | Isn't this basically the same as passing the function to
         | std::bind_front and storing it in a std::function or
         | std::function_ref?
        
       | kazinator wrote:
       | > _It's no wonder GCC is trying to add -ftrampoline-impl=heap to
       | the story of GNU Nested Functions; they might be able to tighten
       | up that performance and make it more competitive with Apple
       | Blocks._
       | 
       | [disclaimer] Without brushing up on the details of this, I
       | strongly suspect that this is about removing the need for
       | executable stacks than performance. Allocating a trampoline on
       | the stack rather than heap is _good_ for efficiency.
       | 
       | These days, many GNU/Linux distros are disabling executable
       | stacks by default in their toolchain configuration, both for
       | building the distro and for the toolchain offered _by_ the system
       | to the user.
       | 
       | When you use GCC local functions, it overrides the linker
       | behavior so that the executable is marked for executable stacks.
       | 
       | Of course, that is a security concession because when your stack
       | is executable, that enables malicious remote execution code to
       | work that relies on injecting code into the stack via a buffer
       | overflow and tricking the process into jumping to it.
       | 
       | If trampolines can be allocated in a heap, then you don't need an
       | executable stack. You do need an executable heap, or an
       | executable dedicated heap for these allocations. (Trampolines are
       | all the same size, so they could be packed into an array.)
       | 
       | Programs which indirect upon GCC local functions are not aware of
       | the trampolines. The trampolines are deallocated naturally when
       | the stack rolls back on function return or longjmp, or a C++
       | exception passing through.
       | 
       | Heap-allocated trampolines have an obvious deallocation problem;
       | it would be interesting to see what strategy is used for that.
        
         | fuhsnn wrote:
         | > Heap-allocated trampolines have an obvious deallocation
         | problem; it would be interesting to see what strategy is used
         | for that.
         | 
         | With -ftrampoline-impl=heap, GCC automatically insert[1] pairs
         | of constructor/destructor routines from libgcc which were built
         | around mmap/munmap.
         | 
         | [1] https://godbolt.org/z/7s5nooMPz
        
       | kazinator wrote:
       | Defininig a callback interface in C without a user context
       | parameter is a capital crime.
        
         | CerryuDu wrote:
         | That's all there is to it. I don't understand the whole
         | obsession with closures.
         | 
         | I've used lambdas extensively in modern C++. I hate them with a
         | passion.
         | 
         | I've also used OCaml. An awesome language where this stuff is
         | super natural and beautiful.
         | 
         | I don't understand why people want to shoehorn functional
         | programming into C. C++ was terrible already, and is now worse
         | for it.
         | 
         | > we're going to be focusing on and looking specifically at
         | Closures in C and C++, since this is going to be about trying
         | to work with and - eventually - standardize something for ISO C
         | that works for everyone.
         | 
         | Sigh. My heart sinks.
        
       | uecker wrote:
       | BTW: I wrote why the lambda design does not fit C well here:
       | 
       | https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3654.pdf
       | 
       | (and I am not impressed by micro benchmarks)
        
         | CerryuDu wrote:
         | From the introduction, your paper seems like a counterproposal:
         | support closures, just not the way others propose. But the
         | paper seems to accept that closures / nested functions,
         | supported at the language level directly, are a "good thing"
         | for C specifically. I disagree with that. When and how has it
         | become the consensus?
        
           | uecker wrote:
           | At the moment there is no consensus for anything related to
           | this. But most people agree that closures are a good thing
           | because they make certain reoccurring programming patterns
           | safer and easier to write. Why do you disagree?
        
       ___________________________________________________________________
       (page generated 2025-12-11 23:01 UTC)