14 ms·
Proposal to add constexpr to C [pdf]
- colonwqbang 5y agoWhat 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.
- deleted 5y ago[deleted]
- nly 5y agoWell, 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 5y ago> 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 5y ago> 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 5y agohave you considered using C11's _Generic feature? It allows you to maunally implement function overloading: https://godbolt.org/z/jxjvnMTPT https://godbolt.org/z/jxjvnMTPT
- zabzonk 5y ago> 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 5y agoMy 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 5y ago> 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 5y agoAlready 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 5y agoMost 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?
- saurik 5y agoI 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 5y ago> 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.
- AlexanderDhoore 5y agoDo 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.
- zarzavat 5y agoIt'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.
- AlexanderDhoore 5y ago"inspect the definition" Yes, that's what I meant with "the compiler can do it".
- zabzonk 5y agoNot given C and C++ separate file compilation.
- zarzavat 5y agoThat 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.
- xvilka 5y agoThey should add `pure` function attribute instead, also maybe the ownership.
- nuerow 5y ago> * 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 5y agoI 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 5y agoI 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.
- rdpintqogeogsaa 5y agoThis is at most tangentially related, but I could never figure out how to submit proposals for the C standard. How does this work?
- enriquto 5y agoIn 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 5y agoGCC has many really good extensions to the C language. Why have they not been adopted? Has nobody submitted them as proposals?
- enriquto 5y agoSure. I'd say that most changes in the C language since 1989 have been first adopted by gcc as extensions, way before they were officially approved.
- rgovostes 5y ago> 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) https://en.wikipedia.org/wiki/Blocks_(C_language_extension)
- dcminter 5y ago
- eps 5y agoThese 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 5y agotypedef 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 5y agoI’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 5y agoProposed 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 5y agoConventional 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 5y agoBecause 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 :)
- ulnarkressty 5y agoDoes 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 5y agoJust 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 https://man.openbsd.org/CMSG_DATA.3
- JustAnonymous 5y agoThis would be something useful, so the committee won't have it.
- ori_b 5y agoThe 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 5y agoCompletely 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.
- WalterBright 5y agoYou might like the way ImportC does it,then. There is no change to the grammar, no new keywords. The obvious stuff just works, whereas in C11 it fails.
- WalterBright 5y agoD's ImportC compiler already does this: https://dlang.org/spec/importc.html#ctfe 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 5y agoHere'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.
- smartaz42 5y agoHmm, isn't square normally x*x?
- mhh__ 5y agoWalter actually retired years ago and replaced himself with an AI. Every now and again there are bugs, move along.
- WalterGR 5y agoMr. Bright is just using TDD. The ‘square’ function works for 2. Next he’ll generalize it to work for more values. Tests aren’t shown. ;)
- deleted 5y ago[deleted]
- WalterBright 5y ago