[HN Gopher] Proposal to add constexpr to C [pdf]
       ___________________________________________________________________
        
       Proposal to add constexpr to C [pdf]
        
       Author : pantalaimon
       Score  : 69 points
       Date   : 2021-10-14 08:10 UTC (2 days ago)
        
 (HTM) web link (www.open-std.org)
 (TXT) w3m dump (www.open-std.org)
        
       | JustAnonymous wrote:
       | This would be something useful, so the committee won't have it.
        
       | xvilka wrote:
       | They should add `pure` function attribute instead, also maybe the
       | ownership.
        
         | nuerow wrote:
         | > * They should add `pure` function attribute instead, also
         | maybe the ownership.*
         | 
         | The C standard committee only adds suggestions that have been
         | presented. If you feel strongly about those features, feel free
         | to put together a proposal like the one that sparked this
         | discussion.
        
           | Ginden wrote:
           | I have experience with proposing new features to languages
           | and that's taxing. You have to deal with constant
           | bikeshedding, provide rationales, states of art analysis for
           | different languages etc. And your proposal can be still
           | stalled for political reasons - eg. there is another proposal
           | and it's expected that certain behaviour will be consistent
           | between both.
        
         | elteto wrote:
         | I think there's a very high bar to clear to choose any other
         | keyword than "constexpr". With "constexpr" code can be compiled
         | without change (at least in this regard) with C or C++
         | compilers, the keyword is the same. Good C and C++ interop is
         | extremely important.
         | 
         | If you choose any other keyword we will end up with nasty macro
         | ifdefs to detect C or C++ and choose the appropriate keyword.
         | And worse, the burden will be on the programmer to do this.
        
       | WalterBright wrote:
       | D's ImportC compiler already does this:
       | 
       | https://dlang.org/spec/importc.html#ctfe
       | 
       | It's a natural consequence of using D's semantic analysis for the
       | C compiler.
       | 
       | I thought about removing it, because it's C, but then decided Vot
       | De Heck and left it in. It's quite nice for the test suite for
       | ImportC, too, as an executable doesn't have to be generated to
       | check the semantics.
       | 
       | P.S. No keyword is required to make it work.
       | 
       | P.P.S. ImportC also allows forward references to declarations,
       | another consequence of using D's semantic implementation.
        
         | WalterBright wrote:
         | Here's ImportC in action:
         | _Static_assert(square(2) == 4, "failed");              int
         | square(int x) { return x * 2; }
         | 
         | 1. there is no need for constexpr keyword. Anywhere a
         | _constant-expression_ in the C grammar appears, compile time
         | function execution is involved.
         | 
         | 2. `square` is forward referenced, but works fine.
        
       | ori_b wrote:
       | The only thing I really want in C is the gradual removal of
       | undefined behavior.
       | 
       | Edit: C isn't perfect, but the biggest usability issues is the
       | subtle footguns from UB. Everything else pales in comparison.
        
         | matheusmoreira wrote:
         | Completely agree! I think C99 is the ultimate version of C,
         | newer standards should be about defining previously undefined
         | behavior and removing deprecated stuff that should not be used
         | like gets and variable length arrays.
        
       | eps wrote:
       | These refer to variables that exist in memory when the program is
       | running:                 const int a;       extern int b;
       | static int c;       volatile int d;
       | 
       | And this refers to something that exists only at compile time:
       | constexpr int z = 1;
       | 
       | This ain't right.
       | 
       | Not that C doesn't need compile-time elements, it'd be better off
       | not copying them from C++ verbatim and implementing in a way that
       | doesn't introduce confusion into basic language concepts such as
       | variables and functions.
        
         | moonchild wrote:
         | typedef int w;
         | 
         | This also refers to something that exists only at compile time.
         | Where's the inconsistency?
         | 
         | constexpr makes a lot more sense as a storage class than
         | typedef.
        
         | elteto wrote:
         | I'm really not seeing what the issue is here. Could you expand
         | on it?
         | 
         | As a programmer why do I have to reason or care whether
         | something is compile time only or not? I don't worry about
         | constant folding but it is a similar thing.
        
           | eps wrote:
           | Proposed constexpr syntax mimics that of a conventional
           | variable, yet it doesn't create one and comes with distinctly
           | different usage semantics. It's a different language element,
           | I see no reason why it should be bundled up with another one.
        
             | elteto wrote:
             | Conventional variable syntax may not create a variable
             | either. The compiler elides as it can or sees fit. This is
             | my point, you don't reason about these details today, why
             | should constexpr be different?
        
               | huhtenberg wrote:
               | Because constexpr and variables are not the same thing?
               | E.g. with a variable you can still always take its
               | address. With constexpr you can't.
               | 
               | Plus 'constexpr' is a patently ugly keyword. Also an
               | important metric to consider :)
        
               | elteto wrote:
               | My point is that arguing about what is a variable is moot
               | in the presence of compiler optimizations. You _might_
               | think that taking and address makes a difference but if
               | the compiler decides that it can elide it will (for
               | example if the taken address never leaves the local scope
               | and the variable is purely local then the compiler might
               | be able to optimize it away).
               | 
               | Regarding ugliness... Idk beauty is in the eye of the
               | beholder. I happen to like constexpr ;)
        
         | Someone wrote:
         | If you refer to that _z_ somewhere, depending on its value and
         | use it might exist as a separate value in the executable, as
         | part of one or more instructions, or not at all (e.g. if you
         | use that _z_ only in _if(z)_ phrases)
         | 
         | > This ain't right.
         | 
         | That's an opinion that's not universally shared.
         | 
         | One could similarly write
         | 
         |  _These refer to variables that can be changed in memory when
         | the program is running:                 int a;       extern int
         | b;       static int c;       volatile int d;
         | 
         | And this refers to something that cannot be changed at runtime:
         | const int z = 1;
         | 
         | This ain't right._
         | 
         | or variations on that theme with _unsigned_ , values vs
         | pointers, int vs long, etc. In all cases, that "this ain't
         | right" doesn't logically follow. Why would yours?
        
       | colonwqbang wrote:
       | What I often find myself lacking in C is a way to overload
       | functions only on pointer constness. Consider
       | 
       | elem *array_get(array *a, int idx)
       | 
       | If I only have a const pointer to a, I cannot use this function.
       | I have to add a second getter for const usecase, or use casting
       | which seems unsafe.
       | 
       | I would like array_get to return a const pointer if the input was
       | a const pointer, and a full pointer otherwise.
       | 
       | Macros can do this. But it would be nice if it worked for
       | functions as well.
        
         | zabzonk wrote:
         | > I would like array_get to return a const pointer if the input
         | was a const pointer, and a full pointer otherwise
         | 
         | Pointers (and other types) don't have "const-ness" attached to
         | them - it's entirely dependent on the declaration of the
         | function. Also, in C++ you can't overload on function return
         | types.
        
         | jstimpfle wrote:
         | My advice is to not bother using const much. It's quirky since
         | data that is "const" for one part of the code might not be for
         | another. But no one has figured out a way to represent such a
         | constness-transition.
         | 
         | You can find this issue with APIs like "strstr()" for example.
         | And IIRC Dennis Ritchie himself raised these concerns when
         | const was conceived. The deeper issue I think is that const
         | should be an attribute of the _code_ (as in, "I won't modify
         | this data"), not of the data. Data is rarely truly constant
         | (RAM cells are obviously writeable).
         | 
         | I use "const" mostly in "const char *" (for string-literals
         | which are pointers to "reasonably const" memory, i.e. read-only
         | mapped memory), and sometimes for function parameters to
         | indicate that the function does not write through the pointer,
         | but as in "strstr()" example this quickly gets quirky. Note
         | that for this simple example you can work around if you take a
         | const-pointer and return an index instead.
         | 
         | Summary: Be practical, don't overthink it.
        
           | pantalaimon wrote:
           | > Data in general is never const
           | 
           | On MCUs const data (along with the whole .text section) is
           | stored in flash which is very much const.
           | 
           | That's also why you want to use const whenever possible so
           | you are not wasting precious RAM.
        
             | jstimpfle wrote:
             | Already changed that to "is rarely truly constant". Also,
             | that flash can be written, even if not during the lifetime
             | of a process.
             | 
             | > That's also why you want to use const whenever possible
             | so you are not wasting precious RAM.
             | 
             | My point is to not overthink placement of "const" in
             | function parameters, local variables, etc. Because those
             | don't make any difference to the compiled output. I already
             | mentioned string literals as one type of "reasonably
             | constant" data, and of course any other thing that goes in
             | the .rodata section (such as globally declared const
             | variables) is as much constant.
             | 
             | To wrap it up, the "const" keyword totally makes sense in
             | global declarations to make them go to .rodata. Using const
             | for type-checking purposes can get quirky on the other
             | hand.
        
             | sgtnoodle wrote:
             | Most MCUs can mutate their flash, though, and most large
             | embedded projects have one or two weird features that
             | depend on mutating flash and then accessing it as const
             | data. Also, Harvard architectures like AVR have different
             | address spaces for flash vs. ram, so const variables still
             | end up copied into RAM unless you qualify the variable
             | types with non-standard decorators.
             | 
             | Being able to explicitly tell the compiler, "you can and
             | should compile this out" seems like a good thing?
        
           | klyrs wrote:
           | I use const frequently, because it helps prevent bugs. When
           | something erroneously mutates immutable data, I want to know
           | that as soon as possible, not months down the road when a
           | corner case gets uncovered. One obvious example of this is
           | thread-safety: you can't write to a const, so the compiler
           | prevents you from introducing data races.
           | 
           | And yeah, sometimes it's annoying write const and non-const
           | versions of the same code. But in my experience, those
           | situations are quite rare and can often be factored out to
           | one-liners; typically, only providing a const version is
           | sufficient.
        
         | [deleted]
        
         | nly wrote:
         | Well, you can slowly turn C in to C++... or you can just use a
         | subset of C++.
         | 
         | As a C++ fan, and to play devils advocate, the argument against
         | CV-qualifier overloading is that it often results in code
         | duplication. I.e. the implementation of both array_get's would
         | be syntactically identical. In modern C++ you can avoid this by
         | making "array*" a template parameter (T*), and let the compile
         | deduce the return type for the function (use auto) from what
         | you actually return.
         | 
         | Many C++ haters don't get that a lot of C++ features build on
         | others.
        
           | nuerow wrote:
           | > _Well, you can slowly turn C in to C++... or you can just
           | use a subset of C++._
           | 
           | Those two are not the same.
           | 
           | It requires far more expertise and experience to be able to
           | strong-arm C++ into generating lean C-like code than just
           | writing C and getting what you want right out of the box.
        
             | nly wrote:
             | > It requires far more expertise and experience to be able
             | to strong-arm C++ into generating lean C-like code than
             | just writing C and getting what you want right out of the
             | box.
             | 
             | Even if that were true, and I protest that it isn't (I feel
             | it's easier to generate good code in C++ than C), adding
             | individual C++ features to C will just erode that ability
             | to reason.
        
         | RicardoLuis0 wrote:
         | have you considered using C11's _Generic feature? It allows you
         | to maunally implement function overloading:
         | https://godbolt.org/z/jxjvnMTPT
        
         | saurik wrote:
         | I mean, in C you can't overload functions on _anything_ ,
         | including even the number of arguments... is this really the
         | most interesting thing to want to overload? I'll claim the C
         | way to do this is to just give yourself an array_get_const.
        
       | dataflow wrote:
       | > C++ has supported compile-time evaluation of first-class
       | functions for over ten years, while C is still limited to using
       | second-class language features in compile-time contexts
       | 
       | It's funny that of _all_ the gazillion features C++ has supported
       | a for well over a decade the C folks have been missing out on,
       | they pick _exactly_ the one superfluous keyword in C++ to
       | cherrypick onto C. You have to wonder what will happen if /when
       | C++ removes the requirement for the keyword later.
        
         | secondcoming wrote:
         | Is it superfluous? I will admit that when I first read about
         | constexpr my first thought was 'why can't the compiler figure
         | this out automatically?'. I assume that compiler vendors all
         | agreed that a new keyword was necessary, they don't add them
         | without reason.
        
           | nuerow wrote:
           | > _I will admit that when I first read about constexpr my
           | first thought was 'why can't the compiler figure this out
           | automatically?'._
           | 
           | I would argue that the main value proposition of constexpr is
           | not what the compiler can figure out automatically but
           | allowing the developer to express where he wants constexpr
           | and afterwards allow the compiler to verify if that's
           | possible.
           | 
           | It's the difference between a soft "nice-to-have"
           | requirements and a hard "must-have" requirement.
        
             | dataflow wrote:
             | > I would argue that the main value proposition of
             | constexpr is not what the compiler can figure out
             | automatically but allowing the developer to express where
             | he wants constexpr and afterwards allow the compiler to
             | verify if that's possible.
             | 
             | If you want to look at it that way, it only applies to
             | variable declarations at best. Not function declarations,
             | which is the most common case of where it's used (and it
             | completely clutters the code).
             | 
             | And honestly, if that was the value proposition, they
             | could've just done it a million other ways. Like think even
             | 'template<auto V> static const auto constant = V' would let
             | you do constant<whatever> and verify it at compile time.
             | Yeah it's C++20 but they could've still done it then or
             | used a different approach, there are lots of ways to
             | address this (attributes, etc.). No need to clutter every
             | function prototype in the language for something that
             | small.
             | 
             | Also I think you're thinking more of consteval than
             | constexpr.
        
               | nuerow wrote:
               | > If you want to look at it that way, it only applies to
               | variable declarations at best. Not function declarations,
               | which is the most common case of where it's used (and it
               | completely clutters the code).
               | 
               | Not really. The whole point of constexpr is to state that
               | an expression is constant, thus the value returned by the
               | function is computed at compile time.
               | 
               | > And honestly, if that was the value proposition, they
               | could've just done it a million other ways.
               | 
               | To me it seems thay annotating a function with constexpr
               | is the clearest and most straight-forward way to go about
               | expressing constant expressions.
               | 
               | > Also I think you're thinking more of consteval than
               | constexpr.
               | 
               | To each his own, but if the whole point is to represent
               | constant expressions then the constexpr keyword seems to
               | be straight-forward.
        
               | dataflow wrote:
               | > Not really. The whole point of constexpr is to state
               | that an expression is constant, thus the value returned
               | by the function is computed at compile time.
               | 
               | That's not even _one_ point of constexpr, let alone the
               | whole point. Putting constexpr in front of a function
               | declaration does absolutely nothing to the codegen. See
               | for yourself: https://gcc.godbolt.org/z/34h6Tanzn
               | 
               | Notice that both h() and f() are called despite being
               | constexpr.
               | 
               | > To me it seems thay annotating a function with
               | constexpr is the clearest and most straight-forward way
               | to go about expressing constant expressions.
               | 
               | Again, it doesn't do what you think (see above). It does
               | absolutely nothing to a function.
               | 
               | > To each his own, but if the whole point is to represent
               | constant expressions then the constexpr keyword seems to
               | be straight-forward.
               | 
               | This isn't an opinion thing. The consteval literally does
               | what you're imagining constexpr does. Just replace
               | constexpr with consteval in the code above. (I could
               | probably argue that one has little use too, but that's
               | not what I'm arguing here.)
        
               | thezilch wrote:
               | What? https://gcc.godbolt.org/z/EzrWW9ss5
        
               | [deleted]
        
               | dataflow wrote:
               | You're seeing the compiler opportunistically make an
               | optimization by taking constexpr as an extra inlining
               | hint. I showed you it's not something you can rely on in
               | my example. You have to realize constexpr only talks
               | about what is _allowed_ to happen, not what is
               | _guaranteed_ to happen. You want consteval for that.
        
               | thezilch wrote:
               | Of course I want consteval, if a later C++ is available
               | to me, but that doesn't excuse you writing constexpr does
               | absolutely nothing, when it clearly does. It's no
               | surprise your example doesn't fold calls without `-O3` or
               | that one could produce a `constexpr` that doesn't fold to
               | a constant (go ahead and try though :>).
               | 
               | But consteval function is also not a literal replacement
               | constexpr. For example, you can't take a pointer to the
               | former. There's a reason they co-exist and are not
               | useless.
        
               | dataflow wrote:
               | > Of course I want consteval, if a later C++ is available
               | to me, but that doesn't excuse you writing constexpr does
               | absolutely nothing, when it clearly does.
               | 
               | consteval wasn't intended to be excusing anything. I was
               | just letting you know you're misunderstanding what
               | constexpr does, and that what you're thinking it's
               | supposed to do is in fact consteval's job.
               | 
               | You seem very confused about language specifications.
               | That GCC and Clang happen to interpret constexpr as an
               | extra "please inline" hint under -O3 is not evidence of
               | constexpr "doing" something, and _certainly_ not
               | justification for including it in the language standard.
               | That 's like saying HN's orange color is "doing
               | something" just because you really like to go eat an
               | orange every time you see it.
               | 
               | I suspect you will have a hard time finding _any_
               | evidence that constexpr was ever intended to be a  "this
               | is technically optional but please really, _really_ try
               | to inline this " hint of sorts to the compiler by the
               | committee.
               | 
               | > But consteval function is also not a literal
               | replacement constexpr.
               | 
               | I didn't say it was.
               | 
               | > For example, you can't take a pointer to the former.
               | 
               | "Therefore constexpr is useful" does not follow from
               | this.
               | 
               | > There's a reason they co-exist and are not useless.
               | 
               | There's a mediocre reason for consteval, and a bad reason
               | for constexpr. The former is probably unnecessary IMO
               | though still of marginal utility, and in any case I can
               | concede there's a debate that _could_ be had there. The
               | latter would be practically useless if the language cared
               | to just make it the implicit default. It 's really only
               | solving a problem it created.
               | 
               | If you're using constexpr as an " _optional but highly
               | recommended inline_ " hint like you're showing me in your
               | examples, you're doing the equivalent of pulling up HN's
               | orange color so it coaxes you (or someone else) to go eat
               | an orange. You are certainly welcome do that (hopefully
               | it's a free country where you live) and I'm not stopping
               | you per se, but it's missing both the letter and the
               | spirit of the keyword(/color) by a colossal margin.
        
           | pjmlp wrote:
           | It can, check the C++ compiler Circle.
           | 
           | https://www.circle-lang.org
           | 
           | Unfortunately it isn't a direction WG21 is willing to adopt.
        
             | wtetzner wrote:
             | I just assumed the constexpr keyword was added to help the
             | programmer ensure that what they were writing could be run
             | at compile time.
        
           | rowanG077 wrote:
           | The compiler can figure it out. But that doesn't solve the
           | problem constexpr was created for. Without constexpr compile
           | time evaluation becomes very brittle. Constexpr is there to
           | help the compiler and developer reach an understanding of the
           | stuff that has to be evaluated at compile time.
        
         | nuerow wrote:
         | > _It 's funny that of all the gazillion features C++ has
         | supported a for well over a decade the C folks have been
         | missing out on, they pick exactly the one superfluous keyword
         | in C++ to cherrypick onto C._
         | 
         | It looks to me that it's a significant improvement that's also
         | a very low hanging fruit, given that C/C++ compilers that
         | already support C++'s constexpr can trivially support it for C
         | as well.
        
           | saagarjha wrote:
           | Not every C compiler is a C++ compiler.
        
           | NavinF wrote:
           | Besides that, I suspect nobody in this thread has looked at
           | what compilers output.
           | 
           | Compare the following programs that multiply 2*2:
           | 
           | https://godbolt.org/z/avsac77aa
           | 
           | https://godbolt.org/z/Mznhrf1sq
           | 
           | The only difference between them is that `len` and `result`
           | are declared constexpr in the first program.
           | 
           | Notice how without constexpr, both clang and gcc generate a
           | slow call to mul() inside main() instead of just calculating
           | 2*2 at compile time.
           | 
           | I'm sure you could use LLVM opt to force to compiler to try
           | harder than -O3 (and maybe that should be the default), but
           | that will also make compile time longer. Real code is way
           | harder to optimize than my 18 lines that are all in 1 file.
        
             | dataflow wrote:
             | > I'm sure you could use LLVM opt to force to compiler to
             | try harder than -O3 (and maybe that should be the default),
             | but that will also make compile time longer. Real code is
             | way harder to optimize than my 18 lines that are all in 1
             | file.
             | 
             | Evaluating code at compile time is _not_ harder or even as
             | much work as than _optimizing_ it. If you ever wrote an
             | interpreter you know that it 's _much_ simpler than
             | optimized codegen. You can evaluate unoptimized code at
             | compile time perfectly fine, and deducing whether that is
             | possible is extremely fast in comparison. Which is why in
             | C++ you see people litter constexpr _everywhere_ they can
             | regardless of whether the code is -O0 or -O3.
        
               | NavinF wrote:
               | Hey, by all means fix clang and gcc so that my example no
               | longer requires a runtime call to mul().
               | 
               | After all, evaluating code at compile time is easy right?
               | 
               | If you succeed in solving this problem in general, feel
               | free to propose a change to the language that allows the
               | use of expressions such as `mul(arr, arr+len)` anywhere
               | you'd normally be required to use a constant. (That's
               | what constexpr already achieves today)
               | 
               | Btw I mentioned that you can make the compiler try harder
               | with LLVM opt because constant-folding is an
               | optimization. I dunno why you bring up codegen.
        
               | dataflow wrote:
               | > Hey, by all means fix clang and gcc so that my example
               | no longer requires a runtime call to mul().
               | 
               | They can just pretend every inline function has constexpr
               | in front of it, and fall back to compiling them if they
               | fail to evaluate it as constexpr. The constexpr doesn't
               | tell the compiler anything it didn't already know or have
               | to verify anyway. And bear in mind much of the standard
               | library already has constexpr in front of it (and that's
               | a pretty strong signal that it should've been implicit
               | IMO). I don't know Clang or GCC's codebases to know
               | exactly what to modify off the top of my head, but I'm
               | pretty sure adding an extra 'constexpr' internally in the
               | front-end would be utterly trivial as far as compilers
               | go. No need for any optimizations to get involved (and
               | it's important to understand this).
        
               | manwe150 wrote:
               | Since the compiler must verify the expression is
               | constexpr-valid, it could annotate that automatically
               | instead. However, I believe that generally the standard
               | requires that the keyword be explicit so that compilers
               | agree on what are legal programs, and don't just declare
               | it to be implementation-defined for what is legal in
               | const-initializer contexts.
               | 
               | But in clang, you'd need an frontend-optimization
               | framework to do that reliably (due to recursion), and it
               | doesn't have one. In llvm, the Attributer framework is
               | still relatively new, but is progressing towards that.
        
             | [deleted]
        
         | jcelerier wrote:
         | > You have to wonder what will happen if/when C++ removes the
         | requirement for the keyword later.
         | 
         | I don't think it's that simple. You need a way to differentiate
         | code that runs at compile time and code that runs at runtime
         | (because at compile time you can afford a "slow" algorithm,
         | while at run-time you'll be calling into a proprietary binary
         | which will do the computation on a GPU or something like that).
        
           | dataflow wrote:
           | > I don't think it's that simple. You need a way to
           | differentiate code that runs at compile time and code that
           | runs at runtime (because at compile time you can afford a
           | "slow" algorithm, while at run-time you'll be calling into a
           | proprietary binary which will do the computation on a GPU or
           | something like that).
           | 
           | You mean std::is_constant_evaluated()? You don't need
           | constexpr to be able to have that.
        
             | jcelerier wrote:
             | but how will you differentiate a call that you want to
             | perform at compile-time vs at run-time? e.g. if you want to
             | run some unit tests to check the two algos, today you'd do:
             | int res = my_algo();         CHECK(res == 123);         ...
             | constexpr int res = my_algo();          CHECK(res == 123);
             | // compile-time version is the same
             | 
             | with                   int my_algo() {            if
             | constexpr(is_constant_evaluated()) {              return
             | 123;           else             return
             | some_lib->very_advanced_computation();         }
             | 
             | how do you do the same without the constexpr keyword ? i'd
             | rather not introduce a template struct just to get a
             | constexpr context, a la                   template<auto
             | Value>         struct manually_constexpr { static constexpr
             | auto value = Value; };
             | CHECK(manually_constexpr<my_algo()>::value == 123);
        
               | petters wrote:
               | "constexpr" does not do what you think it does.
               | 
               | For example, "if constexpr(is_constant_evaluated())" is
               | always true, I think.
               | 
               | See also the new C++ keyword "consteval" (yes, really!)
        
               | jcelerier wrote:
               | ah yes, that'll teach me to type on my phone :)
               | 
               | what do you think that I think that constexpr does ?
               | constexpr in a variable forces the variable's value to be
               | evaluated in a constant expression context (which comes
               | with footgunes, see an in-depth coverage of the issue
               | there: https://gist.github.com/Som1Lse/5309b114accc086d24
               | b842fd803b...)
        
               | dataflow wrote:
               | > but how will you differentiate a call that you want to
               | perform at compile-time vs at run-time?
               | 
               | You could never do that to begin with. The compiler was
               | always free to evaluate your function at compile time
               | (and already did so in some cases).
               | 
               | > e.g. if you want to run some unit tests to check the
               | two algos
               | 
               | Just make two separate functions and compare their
               | outputs. That's what functions are for! So you don't put
               | everything in one giant block of code.
               | 
               | > i'd rather not introduce a template struct just to get
               | a constexpr context, a la
               | 
               | The standard library could do that for you instead of
               | introducing a new keyword. In fact it practically already
               | did so with std::integral_constant; they just need to
               | update it for C++20 to avoid the redundancy.
               | 
               | Or they could've introduced a [[pure]] attribute, or
               | other less intrusive mechanisms. The keyword wasn't
               | necessary for anything you mentioned.
               | 
               | Also, as the sibling comment said, you might want to
               | check out consteval.
        
               | jcelerier wrote:
               | > You could never do that to begin with. The compiler was
               | always free to evaluate your function at compile time
               | (and already did so in some cases).
               | 
               | no, that is false. the constant expression context is
               | specified by the standard - the following will always
               | hold if your compiler is not braindead :
               | https://gcc.godbolt.org/z/zEEbWbhvr
        
               | dataflow wrote:
               | >> You could never do that to begin with. The compiler
               | was always free to evaluate your function at compile time
               | (and already did so in some cases).
               | 
               | > no, that is false.
               | 
               | Your sentence is false, not mine. See below.
               | 
               | > the constant expression context is specified by the
               | standard
               | 
               | Expressions can be evaluated at compile-time outside of
               | "constant expression contexts", under the as-if rule.
               | That's one of the main things compilers do when
               | optimizing code.
        
               | jcelerier wrote:
               | > Expressions can be evaluated at compile-time outside of
               | "constant expression contexts", under the as-if rule.
               | 
               | yes, but that does not make it a constexpr context, which
               | is something explicitely specified by the standard. See
               | my code example: the compiler is obviously able to
               | evaluate foo() at compile time, yet it knows that the
               | evaluation it does at compile time will yield a different
               | result that the one it does in a constexpr context.
        
               | dataflow wrote:
               | > yes, but that does not make it a constexpr context
               | 
               | It seems like we're talking past each other here. You
               | wrote
               | 
               |  _" How will you differentiate a call that you want to
               | perform at compile-time vs at run-time [without
               | constexpr]?"_
               | 
               | And I've been replying to that by pointing out that _your
               | run-time code can still be evaluated at compile time even
               | if you don 't use constexpr_. Heck, I'll point out now
               | that it can still be evaluated at run-time even if you
               | _do_ use constexpr! [1] It 's neither here nor there.
               | 
               | Now you're talking about whether "constexpr contexts" do
               | this, which is a separate question. Incidentally, even
               | constexpr contexts don't distinguish between compile-time
               | and run-time evaluation in anywhere _except the condition
               | itself_ [1], which is not the part you generally care the
               | most about. If you want compile-time evaluation, you need
               | to force its evaluation at a location where it 's
               | required to be evaluated at compile time, which is either
               | a template parameter or a _constexpr variable
               | declaration_.
               | 
               | You seem to be desiring consteval when you talk about
               | constexpr.
               | 
               | (And you still haven't addressed the fact that your unit-
               | test example is better served by having two separate
               | functions!)
               | 
               | > the compiler is obviously able to evaluate foo() at
               | compile time, yet it knows that the evaluation it does at
               | compile time will yield a different result that the one
               | it does in a constexpr context.
               | 
               | Citing this ability as if it's desirable is really
               | strange. If your code does that it's buggy. A good
               | language would outlaw this, not embrace it.
               | 
               | [1] https://gcc.godbolt.org/z/Yhqvqz5Pc
        
               | jcelerier wrote:
               | > "How will you differentiate a call that you want to
               | perform at compile-time vs at run-time [without
               | constexpr]?"
               | 
               | right, I should have wrote "in a constexpr context", e.g.
               | what you find in template<invocations>, etc.
               | 
               | > And I've been replying to that by pointing out that
               | your run-time code can still be evaluated at compile time
               | even if you don't use constexpr.
               | 
               | I don't understand what this does have to do with the
               | rest. That's just an optimization (which is not
               | "consistently observable" and depends on the whims of the
               | compiler). Making a variable constepxr is something that
               | causes consistently observable results, which is much
               | more useful. Incidentally, I have had multiple cases
               | where things that could obviously be computed at compile-
               | time weren't optimized in such a way by clang or gcc
               | unless I did                   constexpr auto foo() {
               | constexpr auto bar = some_complicated_function(...);
               | return bar; }
               | 
               | instead of                   constexpr auto foo() {
               | return some_complicated_function(...); }
               | 
               | with constexpr, if the compiler cannot compute the thing
               | at compile time I get an error (which is good !)
               | 
               | > You seem to be desiring consteval when you talk about
               | constexpr.
               | 
               | what I actually desire deep down is a way to have
               | aribtrary parametrisable contexts, something like a
               | generalized version of
               | http://www.jot.fm/issues/issue_2008_03/article4/ ; having
               | two is already a good start.
               | 
               | > (And you still haven't addressed the fact that your
               | unit-test example is better served by having two separate
               | functions!)
               | 
               | well, because I disagree. If the name my function is e.g.
               | strlen I definitely don't want a strlen_constexpr and
               | strlen_nonconstexpr pair of functions, I want the good
               | choice to be made depending on the context I'm in ; I
               | want to write "strlen" in generic code and have the
               | correct thing happen no matter what.
               | 
               | to give you my general perspective, constexpr could call
               | itself super_bamboozle that I couldn't care less, I just
               | want "multiple worlds" being available in my programming
               | language. what name they take is of very little
               | importance.
        
               | dataflow wrote:
               | > what I actually desire is a way to have aribtrary
               | parametrisable contexts, something like a generalized
               | version of
               | http://www.jot.fm/issues/issue_2008_03/article4/ ; having
               | two is already a good start.
               | 
               | I actually wholeheartedly agree with that. I've wanted
               | something pretty similar for a long time. I just also
               | wholeheartedly disagree on constexpr having been a good
               | start on that.
               | 
               | > Incidentally, I have had multiple cases where things
               | that could obviously be computed at compile-time weren't
               | optimized in such a way by clang or gcc unless I did
               | [...]
               | 
               | And this is one place we circle back to my argument,
               | which is that implicit constexpr should be the default
               | wherever possible. That way you don't e.g. run into
               | situations where you forgot the keyword by accident,
               | because you won't need it to begin with.
               | 
               | > well, because I disagree. If the name my function is
               | e.g. strlen I definitely don't want a strlen_constexpr
               | and strlen_nonconstexpr pair of functions, I want the
               | good choice to be made depending on the context I'm in ;
               | I want to write "strlen" in generic code and have the
               | correct thing happen no matter what.
               | 
               | I think you misunderstood the proposal then. I was saying
               | those functions would be only called directly _for
               | tests_. Everywhere else, you 'd use your strlen() with
               | std::is_constant_evaluated() (or whatever) dispatching to
               | one of those two functions, which would be implementation
               | details hidden away from the user.
        
         | AlexanderDhoore wrote:
         | Do you mean that C++ could have done without `constexpr` and
         | could have used the existing `const`? Because that has been my
         | feeling for a very long time. Why not expand the meaning of
         | const in certain contexts. Compilers know if something can be
         | evaluated at compile-time. No need for me to tell them
         | explicitly.
        
           | pjmlp wrote:
           | Yes, all the constsomething is superfluous, as proven by
           | Circle.
           | 
           | https://www.circle-lang.org/
           | 
           | Unfortunately, there is a big political war ongoing, so
           | instead C++ keeps collecting const.... keywords.
        
             | voldacar wrote:
             | "Constexpr" is possibly the most hideous keyword in any
             | programming language. My eyes vomit a little each time I
             | read it.
             | 
             | They could have just used "pure" like in D, but this is
             | C++, so that would be too sane and obvious.
        
               | pjmlp wrote:
               | Politics, check the outcome of the networking vote.
        
               | hmfrh wrote:
               | Introducing a new keyword means that all existing code
               | that uses the new keyword as an identifier will break.
               | That's why the `constexpr` keyword is deliberately weird.
               | 
               | It's also why they reuse keywords like `using`.
        
               | kevin_thibedeau wrote:
               | They could just use the reserved keyword naming like the
               | C committee does.
        
             | nly wrote:
             | I can't confirm in this specific case but, more often than
             | not, the reason for these redundancies is a fraction of the
             | committee felt uncomfortable with the implicit solution, so
             | the keyword got added.
        
               | pjmlp wrote:
               | There is a video about the story background, where a
               | group of kids play the role of the committee voting down
               | Circle.
        
               | nly wrote:
               | Link?
        
               | pjmlp wrote:
               | Enjoy, https://m.youtube.com/watch?t=2035&v=NNU6cbG96M4
        
             | dataflow wrote:
             | No, not all const is superfluous. You don't want const-able
             | method to be const. And const is a property of the
             | declaration, not the definition. But constexpr _is_
             | superfluous. It 's something the compiler can infer purely
             | from looking at the definition, and it has little to no
             | "design" value like const does.
        
               | dataflow wrote:
               | > You don't want const-able method to be const.
               | 
               | Edit, typo: I meant "You don't want _every_ const-able
               | method to be const. "
        
           | zarzavat wrote:
           | It's not the same. e.g.                  const int x =
           | readInput();
           | 
           | cannot be constexpr. Consider constexpr as a compile time
           | assertion that a given symbol is available at compile time.
           | If you didn't have the constexpr keyword then you would have
           | have to inspect the definition to determine that every
           | subexpression is constexpr.
        
             | nine_k wrote:
             | Why not                 const int x = const foo(bar(y));
             | ?
        
               | mpyne wrote:
               | The compile can (and will) do that at run time, it just
               | won't let the code alter x afterwards (either at compile
               | time or run time)
        
             | AlexanderDhoore wrote:
             | "inspect the definition"
             | 
             | Yes, that's what I meant with "the compiler can do it".
        
               | zabzonk wrote:
               | Not given C and C++ separate file compilation.
        
               | zarzavat wrote:
               | That might be OK in an IDE driven language such as Java,
               | but I doubt the neckbeards writing C in a plain text
               | editor would go for that level of implicitness. In C++ it
               | might be more acceptable since you practically need an
               | IDE since C++11 to resolve all the auto type inference.
        
               | foxfluff wrote:
               | C neckbeard here. I do fully hope and expect and assume
               | the compiler to fold constants and figure out as much at
               | compile time as it can. This is the kind of optimization
               | that doesn't make the code harder to reason about, even
               | when coding with ed, since the logic and ultimate result
               | of these expressions does not change.
               | 
               | Heavy type inference, overloading, and inheritance are a
               | completely different beast and they make the code a lot
               | more opaque.
        
               | [deleted]
        
             | SuchAnonMuchWow wrote:
             | You should check Zig comptime keyword, which does exactly
             | that. Its the feature from zig I miss the most in C.
        
               | User23 wrote:
               | That sounds like a subset of EVAL-WHEN[1].
               | 
               | [1] http://clhs.lisp.se/Body/s_eval_w.htm
        
           | dataflow wrote:
           | Basically, yeah.
           | 
           | You don't even need 'const' for this. Under the as-if rule,
           | subsets of the program could always already be evaluated at
           | compile time and have the result substituted in the program.
           | Compilers already did that when they had the definition
           | handy. Like just do int x = f(5); and then define int f(int
           | x) { return x * 2; } and you'll get int x = 10; in any
           | compiler without any keywords whatsoever. The constexpr
           | keyword just cluttered the code for no good reason.
        
             | NavinF wrote:
             | In theory compilers can always optimize constant
             | expressions, but they don't IRL. See my example above where
             | I multiply the elements of an array containing {2,2}:
             | https://news.ycombinator.com/item?id=28886999
             | 
             | My code is C style and unrealistically simple, yet the
             | compiler can't even constant-fold that.
             | 
             | If you've looked at the output of real compilers, you'd
             | know that it's unrealistic for a language to let you to use
             | the result of an arbitrary function call where you'd
             | normally use a constant.
        
               | dataflow wrote:
               | I'd already replied to you on that example and explained
               | this has nothing to do with optimizations as far as
               | performance and mechanics go. The only relevance of
               | optimizations is to show that the _language semantics_
               | always permitted it. Not to suggest an optimize needs to
               | be run to actually do this.
        
               | comex wrote:
               | It depends.
               | 
               | For one thing, constexpr guarantees that errors will
               | produce compilation failures. (At least it guarantees
               | that when used in certain ways; unfortunately C++
               | overcomplicates things.) In a version of C that doesn't
               | have an explicit constexpr keyword but does allow the
               | compiler to treat arbitrary variables as constants, you
               | could perhaps approximate this by using a value in a
               | context that forces it to be a constant expression...
               | e.g. `const int x = foo(); _Static_assert(x == x);`. But
               | that's a hack. Much better to have an explicit way to say
               | "please evaluate this at compile time".
               | 
               | Also, suppose the user doesn't use an expression in a way
               | that forces it to be evaluated at compile time, but you
               | still want to allow the compiler to do constant
               | evaluation for the sake of faster runtime performance or
               | smaller code size. In this example, should fib(35) be
               | evaluated at compile time or runtime?
               | unsigned int fib(int n) {             return n <= 1 ? 1u
               | : fib(n - 1) + fib(n - 2);         }              int
               | main() {             fib(26);         }
               | 
               | It depends on the user's intent. In this case, evaluating
               | fib(35) takes less than a millisecond at runtime on my
               | computer, but evaluating it as constexpr with clang
               | requires about a full second. (After all, naive fib
               | performs an exponential number of recursive calls.)
               | Sounds like it's probably a job for runtime... unless the
               | user really values runtime performance or code size more
               | than compile times (maybe they're targeting a really slow
               | CPU), in which case they might prefer it to be done at
               | compile time. Best to give them a choice.
               | 
               | Making things worse, the compiler has no real way of
               | knowing how long something will take to constant-evaluate
               | other than trying and seeing. It can give up after a
               | timeout, but if the timeout isn't very tiny, it risks
               | wasting a lot of time on aborted constant evaluation
               | attempts. Therefore, while optimizers already try to
               | perform opportunistic constant folding, they have to be
               | very conservative with it. This problem doesn't occur if
               | the compiler knows that something should be constant-
               | evaluated because the user has marked it as such.
        
               | dataflow wrote:
               | > In this example, should fib(35) be evaluated at compile
               | time or runtime?
               | 
               | In that example, at compile time. If you write fib(35)
               | you deserve to have to wait for the compiler to do it at
               | compile time instead of at run time. (I'm not saying this
               | to be funny. I'm really trying to make a point. You
               | really do need a realistic example to motivate your side
               | of the argument. If they're hard to come up with, that's
               | kind of my point.) And honestly if I wrote that I would
               | fully expect my compiler's optimizer to _already_ waste
               | that time constant-folding anyway; if I was concerned
               | about its compile time I wouldn 't write that even
               | without constexpr.
               | 
               | > Best to give them a choice.
               | 
               | A need for that choice (assuming it's even necessary
               | here, which is debatable, see above) doesn't mean you
               | need a new keyword, especially not for functions. It
               | could've been an attribute, and whatever it is, it only
               | really makes sense on variables, not functions. And
               | whatever it is, turning it into an exclusion instead of
               | an inclusion would probably make sense here, seeing as
               | how so much of the standard library has constexpr in
               | front of it.
        
             | electroly wrote:
             | If nothing else, constexpr as a keyword lets you force it
             | to happen and fail if it can't happen, rather than silently
             | reverting back to runtime execution. I don't think it's
             | certain that C++ will remove the keyword.
        
               | dataflow wrote:
               | constexpr on a _variable declaration_ does that (i.e. it
               | 's still superfluous on function declarations, which is
               | where it clutters code by far the most). But even for
               | that, there was already std::integral_constant which
               | would've forced this, and they could've just updated it
               | to C++20 via template<auto Value> static const auto
               | constant = Value; if they really wanted to. Or added an
               | [[attribute]] for variable declarations, just like how we
               | have [[likely]] etc. No need to introduce a whole new
               | keyword for this, especially not in a ton of other
               | contexts.
        
               | electroly wrote:
               | Those suggestions, honestly, don't sound better than the
               | keyword to me. I think you're taking it as a given that
               | if a keyword can be avoided, it must be avoided, but I
               | don't fundamentally agree with that at all.
        
               | dataflow wrote:
               | I mean your (only?) argument for the constexpr keyword at
               | this point is "it _can_ be a keyword and I feel like it
               | _should_ be, even when I acknowledge it 's redundant"
               | then by all means go ahead. Personally I don't think
               | that's a good way to do language design, but I can't
               | argue with subjective feelings and aesthetics and I was
               | never intending to. I'm pretty sure that's not one of the
               | bases on which it made it into the standard though, and
               | those are what I'm trying to address.
        
         | boulos wrote:
         | ... constexpr isn't superfluous.
         | 
         | The compiler can/could/does absolutely _infer_ that a thing is
         | a compile time constant and do it for you.
         | 
         |  _But_ , if you declare a thing constexpr and someone updates
         | some part of it to be !constexpr, you get a nice compiler
         | error. Without labeling the value as constexpr, you don't get
         | that certainty.
         | 
         | Edit: is the argument that _const static_ is also that? (If so,
         | only for direct initialization of structures  / you still can't
         | have the equivalent of a constexpr function).
        
           | dataflow wrote:
           | > But, if you declare a thing constexpr and someone updates
           | some part of it to be !constexpr, you get a nice compiler
           | error. Without labeling the value as constexpr, you don't get
           | that certainty.
           | 
           | That's not really true. You don't get that "certainty" with
           | constexpr either:                 template<class T> T f(T);
           | template<class T> constexpr T g(T x) { return f(x); }
           | 
           | Notice you won't even get a _warning_ with _-Weverything_
           | under Clang!
           | 
           | > Edit: is the argument that const static is also that? (If
           | so, only for direct initialization of structures / you still
           | can't have the equivalent of a constexpr function).
           | 
           | For _variables_ , const static should probably evaluate at
           | compile time whenever possible, like you mentioned.
           | 
           | For functions, constexpr is _really_ useless (again, see
           | above as just one example) and an inline declaration serves
           | pretty much the same practical purpose. I think you 're
           | thinking of 'consteval', which is at least not _completely_
           | useless, so it 's a little easier to justify. Even then, it
           | should've probably been an attribute rather than a keyword.
        
         | marcodiego wrote:
         | I think you're completely ignoring more radical proposed
         | changes like lambdas: http://www.open-
         | std.org/jtc1/sc22/wg14/www/docs/n2738.pdf and more modern error
         | handling: http://www.open-
         | std.org/jtc1/sc22/wg14/www/docs/n2361.pdf
         | 
         | Also consider that proposals must satisfy http://www.open-
         | std.org/jtc1/sc22/wg14/www/docs/n2021.htm small list of
         | relevant points:                 4. Avoid "quiet changes."
         | 6. Keep the spirit of C.            9. Minimize
         | incompatibilities with C90 (ISO/IEC 9899:1990).            11.
         | Maintain conceptual simplicity.
        
           | dataflow wrote:
           | I'm not ignoring anything, I just mentioned C++ has had a ton
           | of features over C, some well over a decade (and some just
           | about and some newer).
           | 
           | Moreover I can't even see how I could've mentioned lambdas.
           | They have a superfluous keyword? Which one?
        
             | dataflow wrote:
             | Edit: Whoops, just had a chance to read these comments more
             | carefully. I didn't realize you're talking about C rather
             | than C++. I didn't ignore them; I just wasn't aware of
             | those proposals. (Certainly I haven't seen them on HN, and
             | I don't keep up with all the proposals.)
        
           | huhtenberg wrote:
           | Not sure if you were trying to make this point, but as others
           | have noted constexpr almost certainly violates #11 (by mixing
           | run-time and compile-time variables) and through that it also
           | violates #6.
        
           | bonzini wrote:
           | The two things I would add to C are RAII (like GCC
           | __attribute__((cleanup)) and glib's g_autoptr wrappers), and
           | variant types (mostly so that we could have an equivalent of
           | Rust's Result type).
        
             | enriquto wrote:
             | RAII is mostly already there, or at least a C-spirited
             | version of it, thanks to variable length arrays.
             | Unfortunately, there's little compiler support for large
             | vla, both clang and gcc seem to choke on them because they
             | put them on the stack (which is the naive implementation of
             | vla).
        
               | bonzini wrote:
               | How would variable length arrays, for example, help with
               | releasing a mutex on early returns from a function?
        
               | enriquto wrote:
               | They wouldn't, of course! Releasing resources silently
               | (other than the memory of automatic variables) is very
               | un-C-like.
        
               | dataflow wrote:
               | > RAII is mostly already there
               | 
               | >> Releasing resources silently (other than the memory of
               | automatic variables) is very un-C-like
               | 
               | The "R" is literally "resource", right? Sounds like
               | instead of RAII you just meant unique_ptr.
               | 
               | Though I beg to differ on whether releasing memory
               | automatically is any different from releasing other
               | resources as far as being C-like is concerned!
        
       | ulnarkressty wrote:
       | Does anybody have a real case study about the benefits of using
       | constexpr? Everyone is raving about it but their examples of
       | where to use it are absolutely trivial (e.g. return 1+2) and I
       | can't really think of any real-world programs that would attempt
       | to do such computations in a non-dynamic way.
        
         | comex wrote:
         | Just as a starting point, you can look at any existing uses of
         | #define to either define a constant or define a 'function' that
         | can be evaluated at compile time.
         | 
         | For constants, #define is ubiquitous and works fairly well, but
         | it has several disadvantages including:
         | 
         | - When a macro quotes some code, e.g. when assert() shows the
         | expression that failed, any uses of macros inside that code
         | will show up fully expanded. This makes it harder to tell
         | what's going on.
         | 
         | - If the definition of the constant has any complexity to it,
         | it has to be re-evaluated every time it's used.
         | 
         | - Doesn't work with debuggers in some cases (admittedly this
         | could be fixed without a new language feature).
         | 
         | - Difficult to work with for tools that generate FFI bindings
         | for other languages. They can't easily tell what's a constant
         | that should have bindings generated for it, versus what's some
         | random piece of syntax.
         | 
         | An alternative way to define constants in C is with anonymous
         | enum declarations; they avoid all of the above issues, but they
         | can only create constants of integer type - not structs or
         | floating point values - and on some compilers are even more
         | restricted to only creating constants of type `int` or
         | `unsigned int`.
         | 
         | For functions: There are many function-like macros in C APIs.
         | Some must be macros because they're type-generic or otherwise
         | go beyond what a regular function can do. Others could work
         | just as well as inline functions, even in current C, and are
         | macros only because they're inherited from days when compilers
         | couldn't reliably inline functions.
         | 
         | But others are macros because they're meant to be evaluated
         | inside compile-time constants.
         | 
         | For example, from OpenBSD's implementation of the Unix socket
         | API:                   #define CMSG_SPACE(len)
         | (_ALIGN(sizeof(struct cmsghdr)) + _ALIGN(len))
         | #define _ALIGN(p) (((unsigned long)(p) + _ALIGNBYTES) &
         | ~_ALIGNBYTES)
         | 
         | CMSG_SPACE calculates the required buffer size for a control
         | message structure of a given body size. One of the examples
         | from the relevant man page [1] has:                   union {
         | struct cmsghdr hdr;          unsigned char
         | buf[CMSG_SPACE(sizeof(int))];         } cmsgbuf;
         | 
         | which requires CMSG_SPACE(sizeof(int)) to be a compile-time
         | constant.
         | 
         | Mind you, this is all just a starting point. There are more
         | ambitious things you can do with constexpr that people aren't
         | doing with #define because it's not powerful enough. For
         | example: if you use printf, modern compilers have built-in
         | functionality to validate the format string against the
         | argument types. But what if you want to define your own
         | variadic function (for formatting or any other purpose) with a
         | different format string mini-language? With constexpr you can
         | do your own validation at compile time. (It's a bit easier in
         | C++, but it should be doable in C as well if constexpr is
         | added, by using a wrapper macro.)
         | 
         | [1] https://man.openbsd.org/CMSG_DATA.3
        
       | rdpintqogeogsaa wrote:
       | This is at most tangentially related, but I could never figure
       | out how to submit proposals for the C standard. How does this
       | work?
        
         | dcminter wrote:
         | Partial answer I guess? http://www.open-
         | std.org/JTC1/SC22/WG14/www/contributing
        
         | enriquto wrote:
         | In the olden days, the idea was that you did not start by
         | submitting any proposal. First you got your pet language
         | feature implemented (as a non-standard extension) in several
         | major compilers and used in several meaningful code bases. And
         | _then_ you submitted that feature, which was already well
         | understood and under widespread use, to the C standard
         | committee, which would very likely accept it. Nowadays it seems
         | that any old doofus can  "propose" things. Fortunately most of
         | these proposals are not taken too seriously, since the language
         | keeps saying no to nearly all of them. The discussion is
         | interesting though. My pet language extension to C would be
         | closures (local functions that you can return pointers to, thus
         | allocating memory for their local variables); I've seen several
         | proposals for them come and go, without much success.
        
           | matheusmoreira wrote:
           | GCC has many really good extensions to the C language. Why
           | have they not been adopted? Has nobody submitted them as
           | proposals?
        
           | rgovostes wrote:
           | > My pet language extension to C would be closures
           | 
           | Is this not what Blocks are? They are common on Apple
           | platforms.
           | 
           | https://en.wikipedia.org/wiki/Blocks_(C_language_extension)
        
       ___________________________________________________________________
       (page generated 2021-10-16 23:01 UTC)