I wish the C Standard Committe stopped smearing all C++ bullshit in to C. Now that many of the C++ people who promoted those features are abandoning the ship.
It's what you get when your C compilers are implemented in C++.
Why "bullshit"? I looked at the article, and everything looks extremely reasonable, and desirable in C.
* nullptr: fixes problems with eg, va_arg
* better enums: Who doesn't want that? C is a systems language, dealing with stuff like file formats, no? So why shouldn't it be comfortable to define an enum of the right type?
* constexpr is good, an improvement on the macro hell some projects have
* unprototyped functions removed: FINALLY! That's a glaring source of security issues.
Really I don't see what's there to complain about, all good stuff.
nullptr is an overkill solution. The ambiguity could have been solved by mandating that NULL be defined as (void*)0 rather than giving implementations the choice of (void*)0 or 0.
Are there any mainstream implementation where NULL is not typed as (void *)? That seems like a choice that would cause so many problems (type warnings, va_arg issues), i wonder why would anyone do that.
That would have been my preference as well. Either force it to be (void*)0 or, maybe, allow it to be 0 iff it has the same size and parameter passing method.
-constexpr is not anything like constexpr in C++.
-It makes no guarantees about anything being compile time.
-It in no way reflects the ability of the compiler to make something compile time.
-It adds implementation burden by forcing the implementations to issue errors that do not reflect any real information. (For instance you may get an error saying your constexpr isnt a constant expression, but if you remove the constexpr qualifier, then the compiler can happily solve it as a constant expression)
-All kinds of floating point issues.
We should not have admitted this in to the standard, please do not use.
nullptr is the third definition of null. one should be enough, two was bad. why three?
Im in the WG14 so ive been involved in the discussions.
It fails for 2 reasons:
In order to make it easy to implement it had to be made so limited, that it in no way useful.
The second reason, and the real killer, is the "as if" rule. It states that any implementation can do what ever it wants, as long as the output of the application is the same. This means that how a compiler goes about implementing something is entirely up to the compiler. This means that any expression can be compile or execution time. You can even run the pre-processor at run time if you like! This enables all kinds of optimizations.
In reality, modern compilers like gcc, llvm and MSVC are far better at optimizing than what constexpr permits. However since the specification specifies exactly what can be in a constexpr, the implementations are required to issue an error if a constexpr does something beyond this.
>Why is that a problem? It sounds like a benefit. It means that the optimization can't break anything, which to me is kind of the point
As-if is great! but the problem is that constexpr tricks people in to thinking that something is done at compile time, and the as-if rule overrides that and lets the implementation do it when ever it wants. constexpr is a feature over ridden by a fundamental rule of the language.
It has a lot of costs to add to the C language, even if it's just the increased complexity in the documentation, and doesn't effect c99. Every processor, OS, programming language needs used in business needs to fully support a C standard. So adding to C effects every processor and computer architecture, every new OS, every new language.
If you look at CPPreference you can see how much complexity has been added to the C standard in the last few years.
constexpr is also ridiculously simple to implement -- because the existing compilers already do something similar internally for all enumeration constants.
(Enumeration constants are the identifiers defined inside enum xxx {...})
...and most compilers also already silently treat compile time constant expressions like constexpr, an explicit constexpr just throws an error if the expression isn't actually a compile time constant.
A lot of these ARE relevant and useful improvements to the C language itself; constexpr reduces the need for macro-constants (which is nice), ability to specify the enum storage type is often helpful and clean keywords for static_assert etc. are a good idea too.
And getting rid of the "void" for function arguments is basically the best thing since sliced bread.
const is sufficient to eliminate the use of macro-constants with the exception of the use of such constants by the preprocessor itself (in which case constexpr is also inapplicable).
I don’t understand why anyone would use the “auto” variable type thing. In my experience it makes it impossible to read and understand code you aren’t familiar with.
Well, the obvious (?) reason is to type less, and also reduce the risk of doing the wrong thing and using a type that is (subtly) wrong and having values converted which can lead to precision loss.
Also it can (in my opinion, brains seems to work differently) lower the cognitive load of a piece of code, by simply reducing the clutter.
Sure it can obscure the exact type of things, but I guess that's the trade-off some people are willing to do, at least sometimes.
Something like:
const auto got = ftell(fp);
saves you from having to remember if ftell() returns int, long, long long, size_t, ssize_t, off_t or whatever and in many cases you can still use the value returned by e.g. comparing it to other values and so on without needing to know the exact type.
If you want to do I/O (print the number) then you have to know or convert to a known type of course.
This was just a quick response off the top of my head, I haven't actually used GCC 13/C2x yet although it would be dreamy to get a chance to port some old project over.
> you can still use the value returned by e.g. comparing it to other values and so on without needing to know the exact type.
No no no no nonononono. No!
Loose typing was a mistake. I think any sober analyst of C and C++ knows that. The languages have been trying to rectify it ever since.
But dynamic typing was an even bigger mistake. Perversely, it's one caused by a language not having a compiler that can type check the code, which C does.
I want to actually know what my code is doing, thanks. If you want "expressive" programs that are impossible to reason about, just build the whole thing in Python or JS. (And then pull the classic move of breaking out mypy or TypeScript half way in to development, tee hee.)
The only time `auto` is acceptable is when used for lambdas or things whose type is already deducable from the initializer, like `auto p = make_unique<Foo>()`.
There is nothing "dynamic" about what I suggested. There is a real, concrete, static and compile-time known type at all times.
In this case it would be long. I fail to see the huge risk you're implying by operating upon a long-typed value without repeating the type name in the code.
const auto pos_auto = ftell(fp);
const long pos_long = ftell(fp);
I don't understand what you can do with 'pos_long' that would be dangerous doing with 'pos_auto' (again, disregarding I/O since then you typically have to know or cast).
`const long pos_long = ftell(fp);` contains a potential implicit case in the future if the return type of `ftell()` changes.
That's one reason type inference is safer than not inferring. Your program doesn't include semantics you didn't actually intend to be part of its meaning.
Also, I think lambdas would be annoying without it.
I'm not, although it apparently came off that way.
I meant that, to a person reading the code, `auto` tells you about as much about the type you're looking at as no type at all (like in a dynamically typed language).
This is where tooling can help.
An IDE could display the type next to all auto symbols if you want. Or allow you to query it with a keyboard shortcut. This gives the best of both worlds, rather than forcing everyone to write out the types all the time. Sometimes we simply don't care what the exact type is, e.g. if it's an object created and consumed by an API. We still want it type-checked, but we don't want to be forced to write out the type.
There is this guideline of "Almost Always Auto" (https://herbsutter.com/2013/08/12/gotw-94-solution-aaa-style...) and I have been following it for yeears both in my job and my personal projects and I have never been very confused by it or had any sort of bug because of it. I felt very reluctant about using it at all for quite a while myself, but in practice it just makes stuff easier and more obvious. A huge reason it's useful in C++ is generic code (stuff that depends on template parameters or has many template parameters) or deeply nested stuff (typing std::unordered_map<std::string, MyGreatObject::SomeValue>::iterator gets annoying), but it's nice almost everywhere.
Most types are repeated and getting rid of those repetitions makes refactorings a lot easier and gets rid of some source of bugs. For example sometimes you forget to change all the relevant types from uint32_t to uint64_t when refactoring some value and stuff breaks weirdly (of course your compiler should warn on narrowing conversions, but just to illustrate the point, because it is very real).
`size_t` may not be helpful. You can argue that some other specific typedef should have been used in this case, but it's kind of water under the bridge already.
As an example of this, a generic `MAX` macro that doesn't evaluate its arguments multiple times, would be (using said GNU extension of statement expressions):
#define MAX(A, B) ({ auto a = (A); auto b = (B); a>b? a : b; })
As-is, for such things I just use __auto_type, as it's already in the GNU-extension-land.
Here, probably not (with proper arguments at least; without the parens something like `MAX(1;2, 3)` would compile without errors though), but I'm just used to doing it everywhere.
Isn't auto already a keyword for specifying scope? I know it's never used and kind of redundant, but something like `auto x = foo(y);` is a terrible direction for C. Type being abundantly clear at all times is a huge feature.
The accepted proposal does address and preserve `auto`'s use as a storage class, so `auto x = foo(y);` means type deduction based on the return type of `foo`, and `auto int x = 10;` declares an integer with automatic storage duration.
* nullptr: fixes problems with eg, va_arg
* better enums: Who doesn't want that? C is a systems language, dealing with stuff like file formats, no? So why shouldn't it be comfortable to define an enum of the right type?
* constexpr is good, an improvement on the macro hell some projects have
* unprototyped functions removed: FINALLY! That's a glaring source of security issues.
Really I don't see what's there to complain about, all good stuff.