Of course since the old syntax is merely deprecated and not removed, going forward you now have to know the old, bad form and the new, good form in order to read code. Backwards compatibility is a strength but also a one-way complexity ratchet.
At least they managed to kill `auto_ptr`.
Karliss 23 hours ago [-]
I doubt it will be a problem in practice.
Regular variadic arguments in general aren't used very often in C++ with exception of printf like functions. Not rare enough for majority of C++ programmers to not know about them, but definitely much more rare than their use in python. Main reason people know about it at all is printf.
The "new" C compatible form has been supported since the first ISO standardized version of c++ if not longer. There haven't been a good reason to use the "old" form for a very long time. Which means that the amount of C++ code using deprecated form is very low.
Being deprecated means that most compilers and linters will likely add a warning/code fix suggestion. So any maintained project which was accidentally using C incompatible form will quickly fix it. No good reason not to.
As for the projects which for some reason are targeting ancient pre ISO standard c++ version they wouldn't have upgraded to newer standard anyway. So if new standard removed old form completely it wouldn't have helped with those projects.
So no you don't need to know the old form to read C++ code. And in the very unlikely case you encounter it, the way for accessing variadic arguments is the same for both forms through special va_list/va_arg calls. So if you only know the "new" form you should have a pretty good idea of whats going on there. You might lookup in references what's the deal with missing coma, but other than that it shouldn't be a major problem for reading code. This is hardly going to be the biggest obstacle when dealing with code bases that old.
layer8 21 hours ago [-]
The “new” form has been valid since the original 1998 C++ standard, where it was added for compatibility with C. “You now have to know” has therefore already been the case for the past 27 years. Back then the old pre-standard form was kept for backwards compatibility, and is only now being deprecated.
jandrewrogers 19 hours ago [-]
The old-style variadics are rarely seen in C++ these days, never mind this particular edge case. If you working in a vaguely modern version of C++ this largely won’t impact you. You can almost certainly ignore this and you’ll be fine.
Unless you have a massive legacy code base that is never updated, C++ has become much simpler over time. At a lot companies we made a point of slowly re-factoring old code to a more recent C++ standard (often a couple versions behind the bleeding edge) and it always made the code base smaller, safer, and more maintainable. It wasn’t much work to do this either.
To some extent with C++, complexity is a choice.
hrmtst93837 24 hours ago [-]
If two template spellings trip you up, C++ is not your biggest problem. The joke is that each 'cleanup' sands off a tiny rough edge while the commitee leaves the old strata in place, so the language keeps accreting aliases and exceptions instead of dropping dead weight.
tialaramex 23 hours ago [-]
Several times now C++ enthusiasts and indeed the committee have been told the way forward is the "Subset of a superset" that is, Step 1. Add a few new things to C++ and then Step 2. Remove old things to make the smaller, better language they want.
Once they've obtained permission to do Step 1 they can add whatever they want, and in a few years for them it's time to repeat "Subset of a superset" again and get permission for Step 1 again. There is no Step 2, it's embarrassing that this keeps working.
Conscat 1 days ago [-]
PyCuda 2024, used fairly often in certain industries, still contains `auto_ptr` ;-;
vlovich123 23 hours ago [-]
I think Rust has shown a way to remove deprecated interfaces while retaining back compat - automated tooling to migrate to the next version and give a few versions for a deprecated interfaces to stick around at the source level.
ameliaquining 21 hours ago [-]
If you're talking about editions, this isn't how they work at all; every edition continues to be supported forever. (The part about automated migration tooling is true, and nice.)
There've been a few cases where code was unsound and should never have compiled, but did due to compiler bugs, and then they fixed the bugs and the code stopped compiling. These were handled through deprecation warnings with timelines at least several months long (Rust releases a new version every six weeks), but usually didn't have automated migration tooling, and didn't fracture the language mostly because they were rare edge cases that most programmers didn't encounter.
vlovich123 18 hours ago [-]
Editions are still allowed to remove old syntax or even remove APIs - they only can’t break ABIs. So the code is still there once removed from an edition in previous editions, but such symbols don’t even get linked if they’re unused supporting progressive removal. And similarly, I could see editions getting completely removed in the future at some point. Eg rather than indefinitely maintaining editions, in 20 years have a checkpoint version of a compiler that supports the previous 20 years of editions and going forward editions older than 10 aren’t in the build (for example, assuming a meaningful maintenance burden, which is hard to predict when that happens and what a specific policy looks like).
jjmarr 22 hours ago [-]
C++ almost never removes features because of the ABI compatibility guarantees. Programs compiled with older versions of the standard can be linked against newer versions.
This is allegedly because in the 80s companies would write software, fire the programmers, and throw the source code away once it compiled.
Sharlin 22 hours ago [-]
Fixing syntax by definition does not affect the ABI. And Rust has shown that both ABI and API compatibility can be achieved in the presence of several "versions" (editions) of the language in the same build.
irishcoffee 21 hours ago [-]
Rust has shown that it’s yet another language that kind of sort of addresses 3% of the issues c/c++ has, tops.
saghm 20 hours ago [-]
Probably because like 95% of C++'s issues are self-inflicted and don't need to be addressed if you use a different language in the first place, and 1% of them are fundamentally unsolvable by any language.
Sharlin 11 hours ago [-]
Do you actually know Rust or were you just talking out if hour ass? I’d like you to enumerate even thirty problems of C or C++ that Rust doesn’t fix, never mind hundreds (because Rust fixes a metric shit ton of C/C++ problems!)
tialaramex 20 hours ago [-]
I really don't like C++ but it's hard to come up with thirty-odd times as many other terrible problems as the ones Rust addresses.
vlovich123 18 hours ago [-]
lol. A functions module system that’s easy to use and adopted? A package manager? A well implemented hash table? Fast compile times? Effectively no segfaults? Effectively no memory leaks? Comparatively no race condition bugs? A benchmark and unit test framework baked into the language? Auto optimization of the layout of structs? No UB?
I don’t know what you’re counting as “3% of the issues” but if those are the 3%, they sound like massive productivity and safety wins that’s not existed in a language with a similar performance profile to C/C++.
IcyWindows 21 hours ago [-]
Rust is a single vendor. It's not really the same situation.
vlovich123 17 hours ago [-]
Having multiple compiler vendors is a problem IMO not a feature. It fragments the ecosystem - the code compiles fine with this compiler but not this other one. The maintenance of portable Rust code is significantly easier.
I think the way forward is multiple backends (LLVM + GCC) to improve platform support, but a single unified frontend that works correctly on all platforms is a good thing.
zaphar 21 hours ago [-]
There is a single standard committee though. There is really nothing stopping them from shipping tooling that can do the conversions for people. The number of vendors isn't really the problem here. The problem is that the committee shifts that responsibility onto the vendors of the compiler rather than owning it themselves.
advael 1 days ago [-]
This seems pretty good to me just on the level of trying to read C as someone using C++. Parameter packs and variadic templates are easily the most confusing syntax in C++ and cleaning it up is... very welcome
jkaplowitz 1 days ago [-]
Hats off for using "..." in your comment immediately after a valid identifier word and with no comma in between, given the topic of the article.
advael 1 days ago [-]
Hats off for noticing. Not to be taken for granted in an increasingly skimming-oriented world
PaulDavisThe1st 23 hours ago [-]
There remains the problem of defining what the meaning of ...is, is.
advael 20 hours ago [-]
Maybe in another 20 years, ... we will understand
mFixman 1 days ago [-]
I used to slay with this in code golfing competitions from TopCoder, where you had to implement a function to solve a particular problem, thanks to C pointer maths and the gcc generally putting function arguments in order in the stack.
Turns out, these two are equivalent in practice (but UB in the C++ standard):
double solve(double a, double b, double c, double d) {
return a + b + c + d;
}
double solve(double a ...) {
return a + 1[&a] + 2[&a] + 3[&a];
}
mananaysiempre 1 days ago [-]
> Turns out, these two are equivalent in practice
Not in the x86-64 SysV ABI they aren’t. The arguments will be passed in registers (yes, even the variadic ones), so how your compiler will interpret 1[&a] is anybody’s guess. (For me, x86_64-unknown-linux-gnu-g++ -O2 yields, essentially, return a+a+a+a; which is certainly an interpretation. I’m also getting strange results from i686-unknown-linux-gnu-g++ -O2, but my x87 assembly is rusty enough that I don’t really get what’s going on there.)
Clang does the sensible thing with UB and just returns poison (a form of undefined value) in both cases, which manifests as do nothing on x86-64 and load a zero value on i386, because you need to push something on the stack and fldz is one of the cheapest ways to push something. Meanwhile, gcc is in both cases for the UB variant returning a + a + a + a;
FWIW, going back through older gcc versions, it seems i386 gcc stops implementing 'add the arguments' in version 11.1, although it's not until 15.1 that it has a sensible assembly for 'a + a + a + a'. The x86-64 gcc version is broken in 4.0 (where it stops copying the register arguments to the stack when va_start isn't called, I guess). Then it's adding xmm0 to the top 3 values on the stack until 11.1, when it's adding 'a + a + a + a', although not sensibly until version 15.1.
Sharlin 22 hours ago [-]
> return a+a+a+a; which is certainly an interpretation.
Zero is the only valid index of &a, so I presume the compiler just assumes that all the indexes in 1[&a] + 2[&a] etc must be zero. Even though they're in this case compile-time constants – the optimizer could check but why bother given that it's UB anyway. I assume modern C/C++ compilers have some flag to diagnose indexing that's known to be OOB at compile time.
mananaysiempre 22 hours ago [-]
I’m so used to sticking -Wall in my compilation flags the moment I write a build script that I didn’t realize it wasn’t there for this quick experiment. Yes, thank you, there are indeed diagnostics once you ask for them:
test.cpp: In function ‘double solve(double, ...)’:
test.cpp:4:20: warning: array subscript 1 is outside array bounds of ‘double [1]’ [-Warray-bounds=]
4 | return a + 1[&a] + 2[&a] + 3[&a];
| ~~~~^
test.cpp:3:58: note: at offset 8 into object ‘a’ of size 8
3 | extern "C" __attribute__((noinline)) double solve(double a, ...) {
| ~~~~~~~^
[repeat twice more for the other two accesses]
The cast in the invocation can be macro-ed away. And the best thing is, the actual stack layout and data movement/shuffling is pretty much identical to the approach with <stdargs.h>, and with no UB or compiler intrinsics.
kevin_thibedeau 1 days ago [-]
That's a compound literal, not a cast.
flqn 21 hours ago [-]
This is a good change. Potentially ambiguous to read syntax is being made clearer in a way that harms no previous code substantially.
I sometimes wonder if the comments that say nothing more than "C++ is too complicated" are from people who use it regularly, much less people who are even commenting on TFA
saghm 20 hours ago [-]
I don't fully understand the connection between your two paragraphs. It's not inconsistent for the language to be too complicated for it to be a good change.
I'm also not totally convinced that someone not using a language regularly means their view on it being too complicated must be invalid; I would fully expect someone who views it as too complicated to try to avoid using it, and there are enough people doing that, it might be a cause for concern. That doesn't necessarily mean they're right, but without further context it also doesn't mean their opinion isn't relevant.
rusakov-field 24 hours ago [-]
Clarity and Elegance of Syntax > Backwards compatibility.
In my opinion anyway. C++ feels so bloated these days.
zlfn 1 days ago [-]
C++ seems to be constantly getting complicated. If the major version were to change, there wouldn't be any need for backward compatibility with the existing code, and it would have been okay to delete that syntax while creating an automatic formatter.
PaulDavisThe1st 23 hours ago [-]
>If the major version were to change, there wouldn't be any need for backward compatibility with the existing code,
I have no idea where you get this idea from. I expect gcc v28 to be able to compile C++ from 2008, and I'm not alone in that.
maccard 21 hours ago [-]
I completely agree with you.
That said, I wish code written for gcc v28 didn't have to be binary compatible with C++ that was last compiled in 2008...
PaulDavisThe1st 19 hours ago [-]
It isn't.
maccard 11 hours ago [-]
And yet GCC and MSVC both refuse to break ABI and have done so for over a decade.
dnmc 1 days ago [-]
Are you suggesting we move to C++++?
zlfn 1 days ago [-]
It's already there. It's called C#
HackerThemAll 1 days ago [-]
Well, C# also has its quirks already. Like the crippled finalizers which are never to be used. If the IDisposable interface had been correctly designed, finalizers could become be the "public void Dispose(void)". Or the manual passing of Task in case of async methods, which is... kinda smelly.
tialaramex 1 days ago [-]
It's possible you didn't realise, but C# is sometimes said to be named that way because # is the symbol you get if you draw ++ small and then on the line below ++ again. Hence C++++
All languages have some spikier edges, there are no languages I know where I think "Well, even if we could start over I have no idea how to improve this". What's notable about C++ is just how rich that "could do better" seam is, so very many of their defaults are wrong, so many of their keywords are the wrong word, so many of their standard library features are allowed, sometimes even mandated to be crap.
kstrauser 1 days ago [-]
I don’t know if that’s true or not, but while the thought never crossed my mind before your comment, it’s now canon in my mind. Yes, C# is spelled C++++ with a ligature.
Sharlin 22 hours ago [-]
The name is actually pretty clever (the fact that it was originally un-googlable notwithstanding). There are at least three interpretations:
* "C sharp" as in "C but higher",
* C with four pluses, and
* a homophone of "see sharp"
HackerThemAll 1 days ago [-]
I think you meant to get that to the original poster, who seems to imply C# is the flawless, bestest incarnation of C\+\+(\+\+)+.
cyberax 22 hours ago [-]
This is a fundamental problem with GC-ed languages. You can't get predictable finalization, so IDisposable can never be implemented reliably.
layer8 21 hours ago [-]
“#” is just two “+”. Count the lines.
m-schuetz 1 days ago [-]
Personally I like C+. Picking the nice parts of C++, but skipping all the nonsense. I just wish C++ hadn't deliberately screwed up designated initializers with mandatory ordering. The C version of it that allows out-of-order assignments is clearly superior.
dist-epoch 1 days ago [-]
Didn't you read the article? That form is deprecated. The recommended one is C,++,++
PaulDavisThe1st 23 hours ago [-]
You clearly didn't read it either. Going forward, it will be C++...
recursivecaveat 21 hours ago [-]
I mean this is extremely minor, but the more incompatibility you create the slower the uptake will be. In the extreme you could create a Python 2->3 situation over old syntax.
paulmooreparks 20 hours ago [-]
Note to the author of TFA: The moment I get a sign-up modal on any site, I close the tab and move on.
throwaway2027 1 days ago [-]
C++ got too complicated after C++23 I went back to C.
FartyMcFarter 1 days ago [-]
You can always restrict yourself to a subset of C++ that takes advantage of RAII (resource handling is extremely painful in C), and get performance benefits like move semantics, without the insanely complex stuff.
I love C, but C++ has worthwhile advantages even if you heavily restrict which features you use.
mianos 20 hours ago [-]
I do this and my C++ is really like python to code in.
But, if you work in a team, there will always be a bunch of people who come in and start using all sorts of exotic shit for their resume or hobby interest.
Conscat 3 hours ago [-]
Simply by asserting "we support MSVC", most `exciting` C++ will never be touched in a codebase.
Conscat 1 days ago [-]
No offense intended to your perspective, but I do find it a little amusing that C++23, which was generally considered a disappointingly small update due to COVID complications, was the breaking point in complexity.
The difference being that P1219R2 was actually a revised proposal from 2019 not 2021.
lasgawe 1 days ago [-]
learned something new. thanks for the article.
HackerThemAll 1 days ago [-]
Yes, but no. I learned C++ in '90s when it was C with classes and some other noise added by Stroustrup. During the some 25 years that followed it had became a mess that's insanely hard to work with. I'm not going back to this language. I prefer plain C or Rust, leaning towards Rust when I fully comprehend the lifetime and borrow checker. Or when I have the luxury of having a GCed runtime, then the .NET with its easiest C# language with wonderful abundance of great libraries is the best choice. Nobody was ever fired for using .NET (for right purposes).
PaulDavisThe1st 23 hours ago [-]
Tiring how often this needs to be said, but if you want "C with classes", you can just use C++ that way.
I've been using C++ for more than 30 years (I added thread_local to Cfront back in the early 90s), and while the language has grown dramatically in that time, there is fundamentally nothing that would prevent me from writing "C with classes" using the modern version.
I don't do that because I also like RAII, and polymorphism, and operator overloading and ...
I've never used .NET and could not imagine any scenario under which I would. The libraries that matter to me are mostly written in C or C++ and there are more of them than I'd ever need, mostly.
zabzonk 22 hours ago [-]
> nothing that would prevent me from writing "C with classes" using the modern version.
Or indeed "C without classes", just with some extra type-checking.
And of course K&R used Stroustrup's C++ compiler to build and test the code for TCPL 2nd Ed.
QuadmasterXLII 23 hours ago [-]
Languages are both read and written, restrictions like OP is pining for are fundamentally for reading. As such, it is not terribly helpful that they can opt in to restrictions when writing.
PaulDavisThe1st 19 hours ago [-]
What you read is what was written.
useftmly 22 hours ago [-]
[dead]
Rendered at 20:19:35 GMT+0000 (Coordinated Universal Time) with Vercel.
At least they managed to kill `auto_ptr`.
Regular variadic arguments in general aren't used very often in C++ with exception of printf like functions. Not rare enough for majority of C++ programmers to not know about them, but definitely much more rare than their use in python. Main reason people know about it at all is printf. The "new" C compatible form has been supported since the first ISO standardized version of c++ if not longer. There haven't been a good reason to use the "old" form for a very long time. Which means that the amount of C++ code using deprecated form is very low.
Being deprecated means that most compilers and linters will likely add a warning/code fix suggestion. So any maintained project which was accidentally using C incompatible form will quickly fix it. No good reason not to.
As for the projects which for some reason are targeting ancient pre ISO standard c++ version they wouldn't have upgraded to newer standard anyway. So if new standard removed old form completely it wouldn't have helped with those projects.
So no you don't need to know the old form to read C++ code. And in the very unlikely case you encounter it, the way for accessing variadic arguments is the same for both forms through special va_list/va_arg calls. So if you only know the "new" form you should have a pretty good idea of whats going on there. You might lookup in references what's the deal with missing coma, but other than that it shouldn't be a major problem for reading code. This is hardly going to be the biggest obstacle when dealing with code bases that old.
Unless you have a massive legacy code base that is never updated, C++ has become much simpler over time. At a lot companies we made a point of slowly re-factoring old code to a more recent C++ standard (often a couple versions behind the bleeding edge) and it always made the code base smaller, safer, and more maintainable. It wasn’t much work to do this either.
To some extent with C++, complexity is a choice.
Once they've obtained permission to do Step 1 they can add whatever they want, and in a few years for them it's time to repeat "Subset of a superset" again and get permission for Step 1 again. There is no Step 2, it's embarrassing that this keeps working.
There've been a few cases where code was unsound and should never have compiled, but did due to compiler bugs, and then they fixed the bugs and the code stopped compiling. These were handled through deprecation warnings with timelines at least several months long (Rust releases a new version every six weeks), but usually didn't have automated migration tooling, and didn't fracture the language mostly because they were rare edge cases that most programmers didn't encounter.
This is allegedly because in the 80s companies would write software, fire the programmers, and throw the source code away once it compiled.
I don’t know what you’re counting as “3% of the issues” but if those are the 3%, they sound like massive productivity and safety wins that’s not existed in a language with a similar performance profile to C/C++.
I think the way forward is multiple backends (LLVM + GCC) to improve platform support, but a single unified frontend that works correctly on all platforms is a good thing.
Turns out, these two are equivalent in practice (but UB in the C++ standard):
Not in the x86-64 SysV ABI they aren’t. The arguments will be passed in registers (yes, even the variadic ones), so how your compiler will interpret 1[&a] is anybody’s guess. (For me, x86_64-unknown-linux-gnu-g++ -O2 yields, essentially, return a+a+a+a; which is certainly an interpretation. I’m also getting strange results from i686-unknown-linux-gnu-g++ -O2, but my x87 assembly is rusty enough that I don’t really get what’s going on there.)
Clang does the sensible thing with UB and just returns poison (a form of undefined value) in both cases, which manifests as do nothing on x86-64 and load a zero value on i386, because you need to push something on the stack and fldz is one of the cheapest ways to push something. Meanwhile, gcc is in both cases for the UB variant returning a + a + a + a;
FWIW, going back through older gcc versions, it seems i386 gcc stops implementing 'add the arguments' in version 11.1, although it's not until 15.1 that it has a sensible assembly for 'a + a + a + a'. The x86-64 gcc version is broken in 4.0 (where it stops copying the register arguments to the stack when va_start isn't called, I guess). Then it's adding xmm0 to the top 3 values on the stack until 11.1, when it's adding 'a + a + a + a', although not sensibly until version 15.1.
Zero is the only valid index of &a, so I presume the compiler just assumes that all the indexes in 1[&a] + 2[&a] etc must be zero. Even though they're in this case compile-time constants – the optimizer could check but why bother given that it's UB anyway. I assume modern C/C++ compilers have some flag to diagnose indexing that's known to be OOB at compile time.
Err no; https://gcc.godbolt.org/z/sW3ea58oc
They're equivalent on GCC.
I sometimes wonder if the comments that say nothing more than "C++ is too complicated" are from people who use it regularly, much less people who are even commenting on TFA
I'm also not totally convinced that someone not using a language regularly means their view on it being too complicated must be invalid; I would fully expect someone who views it as too complicated to try to avoid using it, and there are enough people doing that, it might be a cause for concern. That doesn't necessarily mean they're right, but without further context it also doesn't mean their opinion isn't relevant.
In my opinion anyway. C++ feels so bloated these days.
I have no idea where you get this idea from. I expect gcc v28 to be able to compile C++ from 2008, and I'm not alone in that.
That said, I wish code written for gcc v28 didn't have to be binary compatible with C++ that was last compiled in 2008...
All languages have some spikier edges, there are no languages I know where I think "Well, even if we could start over I have no idea how to improve this". What's notable about C++ is just how rich that "could do better" seam is, so very many of their defaults are wrong, so many of their keywords are the wrong word, so many of their standard library features are allowed, sometimes even mandated to be crap.
* "C sharp" as in "C but higher",
* C with four pluses, and
* a homophone of "see sharp"
I love C, but C++ has worthwhile advantages even if you heavily restrict which features you use.
I guess that's a preview how C++ require a lifelong commitment.
The difference being that P1219R2 was actually a revised proposal from 2019 not 2021.
I've been using C++ for more than 30 years (I added thread_local to Cfront back in the early 90s), and while the language has grown dramatically in that time, there is fundamentally nothing that would prevent me from writing "C with classes" using the modern version.
I don't do that because I also like RAII, and polymorphism, and operator overloading and ...
I've never used .NET and could not imagine any scenario under which I would. The libraries that matter to me are mostly written in C or C++ and there are more of them than I'd ever need, mostly.
Or indeed "C without classes", just with some extra type-checking.
And of course K&R used Stroustrup's C++ compiler to build and test the code for TCPL 2nd Ed.