If everyone just runs a static analyzer after compiling you could have best of both worlds. For example the tool would complain if you don't use 'override'. Problem is that not everyone runs the same tool. So at work I would like to compile with (for example) -Wconversion (warn about implicit conversions that lose precision). But this is impossible because Qt headers raise so many warnings on this. And because C++ has no module system I can either 1) fix all of Qt or 2) don't add the warning and keep writing old C++. I think you can guess what I will do.
Definitely recommend using -isystem for third party libs such as Boost, ACE, QT, Protobuf, etc. I strive for warning free code in my own, but dont have much control over the libs I use. Warnings from Protobuf are especially annoying due to Googles ill-thought-out disregard for signed/unsigned comparison (and their bullshit rationale in their style guideline) and continued use of NULL/0 as a nullptr constant (they only support C++11 and greater, no reason to not use nullptr now). I strive for clean compilation with "-Wall -Wextra -Wzero-as-null-pointer-constant -Werror", but alas, hard to implement after the fact in legacy code.
clang-tidy's for code cleanup. For serious static analysis, you need scan-build, which is dearly missing this functionality[1]. This is a serious issue for larger codebases with many external dependencies like LibreOffice.[2]
Just to play with it a bit. Unenforced coding standards can't be relied on. So you want something like lint (of old), tidy-clang, or git check-in hooks to help enforce. At that point it becomes tempting to say "if it is part of the language, it should be in the compiler." But back to your point- it is easier for small groups to enforce their own standards than to change the compiler for everyone.
I always make two header files with pragmas to disable compiler warnings and pops and then wrap any offending 3rd party header inclusions between those.
You can't remove features from a language, that creates a new language instead. The transition then takes years. Haven't people realised this since the Perl 5/6 and Python 2/3 transitions?
I'm a little bit surprised to see this coming from scott meyers, who I generally assume to have much better judgment than I do when it comes to c++.
I would think (or at least hope) that there are not many new projects being started in c++ these days. with this assumption, it seems like the main focus for c++ today should be on adding features that enable developers to incrementally rewrite old code with a view towards increased safety. range-based for is a great example of this. a large portion of unchecked vector accesses within loops can be trivially rewritten with range-based for to be much safer, and a small team can simply fix them one by one as they quash bugs.
on the other hand, removing NULL all at once in a legacy codebase could be almost impossible for a small team. I've seen many unfortunate instances where the code actually relies on NULL being the integer '0'. fixing this kind of thing across thousands of files would be an absolute nightmare.
I am certainly sympathetic to the idea that the code that will be broken by these types of changes is sloppy and should be rewritten anyway, but this is unlikely to actually happen. most resource-constrained teams are just going to freeze their projects at c++yy and never benefit from any new features.
edit: I partially retract this post. the gradual 10-year deprecation process he specifies seems reasonable enough. I still question whether making c++ less confusing to newcomers is a good use of resources. there's really not a lot of situations where it makes sense to start a new project in c++.
I'm pretty sure that given the overall large increase in the amount of programmers, there are more new C++ projects being created this year than there were new software projects overall when c++98 was standardized. Consider that in the US alone, there were ~600k developers in 2002, and nowadays the estimates are at ~4.5 million.
> I would think (or at least hope) that there are not many new projects being started in c++ these days.
I would imagine there are fewer new projects in C++ than, say, JavaScript, and fewer new projects in C++ than old projects in C++.
But C++ is absolutely still a live language! For the simple reason that there is no alternative which can work in all its significant niches (systems, realtime, embedded, HPC) and which is mature. Rust is on its way. D could be on its way. Ada never caught on widely, for some reason.
Ada never caught on, because its compilers were too expensive and no OS vendor included it on their standard SDK, thus hardly anyone would pay extra for additional languages beyond those on the SDK.
C++ caught on, because it came from AT&T and was embraced by C compiler vendors, thus landing in all OS SDKs.
Being part of a platform SDK is usually the path to fortune, for any language in platforms that manage to win widespread usage.
Ada was also too slow to compile with the computer systems of the day. I remember a HW company coming on site with a demo (contained on 9 track tape, of course). Compilation of a couple thousand lines of ada took all day (5+ hours). In that era, couple of thousand lines of fortran was 10 minutes. Big difference.
Ada was ahead of it's time. Still the language of choice when you care more about non-functional requirements.
New robotics and vision systems are still very much using c++. Real time object tracking with sensor fusion requires careful handling of resources all of which needs to fit into a larger framework. C++ is the best choice to be able to develop a complex OOP architecture and still be able to get the efficiency where you need it.
>I would think (or at least hope) that there are not many new projects being started in c++ these days.
I doubt there was any fall to the number of C++ projects started. For the domains C++ is used (OSes, premium apps the likes of Office, Photoshop, 3D, video editing, DAWs, etc, AAA games, networking, databases, number crunching, etc), there's no substitute with the same number of compilers, ecosystem, maturity, and programmer base. Rust doesn't even come close.
The fact that these transitions were so painful doesn't mean that all breaking changes have to be so painful. With Meyers' 'magic wand', the transition is eased quite a bit. But another important component of a smooth transition is a 'carrot', a new feature that's so compelling everybody will want to move to the new use the new version. If a C++ with major breaking changes would also halve compilation time for example, most people would switch in a heartbeat.
That assumes that compilation times is a number one prio for all users. Halving compilation times certainly is worth something, but the cost will have to compare well to other options of reducing compilation times such as using distributed builds etc.
In the end it's really hard to force breaking changes for systems that are working sufficiently well. If I have something that I'm satisfied with (after all, I chose to use C++ over Go, c#, D, Ada, Pascal, etc., why not choose C++17 over some hypothethical incompatible C++22)
As long as you can link old-C++ and new-C++ together, there shouldn't be any big problems. You'll write your new code in new-C++ and wrap your old code in extern "old-C++". The same way you can mix C code in C++ projects today.
> All we need is a magic wand that works instantly and flawlessly.
> That makes clang-tidy, if nothing else, a proof of concept.
More like a proof of failure. Apply clang-tidy's transformations to source code and now you've now got one gigantic merge conflict to resolve every time you merge from upstream. That's partially fixable if you script your integration, or your integrators have good checklist discipline (they don't) and apply clang-tidy to new upstream commits before trying to merge them, and you've properly documented that.
Downstream is more problematic. And in my experience, large merge conflicts like this are just begging for hard to spot bugs introduced by mismerging commits - much more common than I've noticed bugs from passing 0 to pointers or NULL to non-pointers. To add insult to injury, it'll fail to finish the job - for example, trivial edge cases like 0 being used in a macro which is interchangeably used to initialize ints and nullptrs depending on context - so now you need manual intervention to actually fix up the code enough to actually "break the egg".
Not to mention NULL in C headers, as mentioned in the blog comments, being not a great thing to get rid of.
> Experience shows that relying on compiler warnings to inform programmers about "bad" practices is not reliable.
Get a bigger CI build matrix. This is a criticism of the implementation, and perhaps those who don't use warnings-as-errors - they have much bigger problems than a confusing 0/NULL/nullptr trifecta though. Standardize some warnings? Sure! We've been adding things like [[nodiscard]] that, while still not requiring warnings, strongly encourage them to the point of being just a hair's breadth away from standardization.
Several compilers don't even like enabling new warnings by default - hence the -Wall -Wextra -Weffc++ -pedantic -etc -etc -etc dance, which still doesn't get everything you might want. If you want to change the culture around that so we opt out of warnings instead of opting in, sure, I'm on board with that. We already have the tooling to crank those up for your own code while using more permissive settings for third party code you'd rather not modify/break.
If you can't convince compiler vendors to warn more by default, you're going to have even less luck getting them to break code by default (unless you can trick them into thinking it's an optimization).
TL;DR: We've got more reasonable, less drastic tools. Maybe push those to be used more efficiently, instead of inviting a new Python 3 fiasco. I'm sure I'm not the only person who would jump to Rust (or Go, or Nim, or ...) instead of to C++vIncompatible - because if you're going to make a breaking change, why not break enough things to make it worthwhile?
Python 3 - fiasco or not - happened and went away. C++ fiasco is still ongoing with no end in sight - both on tooling side and language complexity side.
Maybe it's gone for you. Great, I'm happy for you. I'm still dealing with the aftermath of not having a clean incremental upgrade path, so you can see why I'm not in favor of adding more?
At work, we recently postponed a transition to C++17 due to library compatibility issues. Which is a shame - I'd really like to be using [[nodiscard]] for some APIs on MSVC (we're using vendor attributes on clang at least, but not everyone compiles with clang first.)
I'm sure you understand, then, why I'm hesitant to make upgrading even harder.
> In C++17 and any upcoming C++ standard you can still use all three of: NULL, 0 and nullptr just to name one issue.
We agree there's a lot rotten with C++. I have a large list of complaints about C++ that's been growing for well over a decade now, but that's just what makes suggestions like this doubly frustrating. There's so much wrong with C++ that could be fixed, and non-issues with serious consequences to their "fixes" like "I can still use NULL" come up, distract and waste developer time (meaning less time can be spent on actual issues with real consequences), that suggest wasting even more time fixing what isn't broken. It's like some compulsion to make old code look new and shiny at all costs, even if s/NULL/nullptr/ is about as effective as putting lipstick on a pig in that regard.
> This has nothing to do with vendor refusing to upgrade.
I'm confused as to how an upgrade roadmap is "refusing to upgrade". You can see some of the minimum patch version bumps they've required in the tables I linked. Despite the fact that it's going to break things and leave downstream on older versions until they get a chance to make the upgrade. I've done the downstream fixes for Maya plugins before (D3D9 -> D3D11 for plugins that hook into the renderer), I'll probably end up doing the fixes for Maya python scripts broken by the 2 -> 3 upgrade whenever that lands too.
The only way this is unrelated is if you live in a closed ecosystem where you have perfect control over your dependencies, no upstream or downstream to break compatability with, no branching to worry about, and a small or borderline inactive codebase where sweeping changes are trivial.
>We've got more reasonable, less drastic tools. Maybe push those to be used more efficiently, instead of inviting a new Python 3 fiasco.
Most people I know who complain about the Python 3 transition are not heavy Python programmers.
Migrating to Python 3 was certainly a pain, but not really a major one. The number of developers who fled Python because of this is miniscule. If the Python 3 transition is the poster child of "things going wrong" with backward incompatible changes, I would heartily recommend other languages make those incompatible changes.
I believe that moving a 500k loc code base qualified us as semi-heavy. And relying on packages that didn't move qualified us as stuck.
Now - don't get me wrong: i/we liked python2. There was little wrong with the language or sticking with it. But please don't think the cost of migration was a weekend of lost coffees.
For the transition from Python 2 to 3 the Python team released just such a conversion tool, aptly named "2to3." [1] This was better than handy but the transition from 2 to 3 was still lengthy and painful. In practice many of the suggested changes were unnecessary or at least needed human review (e.g. suggesting changing "for n in range(1,11)" to "for n in list(range(1,11))". Thanks, 2to3, but that code is still correct and actually faster with the iterator version of range().) Another problem was that, just like it says on the tin, 2to3 produces a version of code that only runs under Python 3, whereas most library authors during the transition time wanted a version that would run under both 2 and 3 a la the six[2] library.
So while a one-way automated refactoring script sounds like a good idea, and is strictly better than just breaking backwards compatibility and expecting everyone to deal, it wasn't an unqualified success for Python.
This sounds like a terrible idea. You can provide a way for people to opt out of legacy behavior, but don't break them outright unless you want to lose your most faithful, long-term users.
Anyone who has programmed with Objective-C (or Swift) for years knows Apple's language deprecation cycle. Write code one year, the next year you are flagged with a deprecation warning -- Xcode of course will help you upgrade your code. Your unchanged code will probably work for another year and then suddenly it is an error. The "magic wand" of Xcode / Clang helps you thru this transistion. Apple likes to break eggs.
Has Objective-C been deprecated? I was under the assumption it's still fully supported. It obviously won't see the same level of updates, but it's also been around for a longer period of time to mature.
I honestly like Objective-C and prefer it, but I have been using Swift mostly for the iOS projects I have done in recent year or 2. Mostly out of curiosity though.
Obj-C has not been deprecated. And in fact the only parts of Obj-C itself that have actually been deprecated were during the migration to "Obj-C 2", where a slew of runtime functions (that nobody used) were removed, as well as direct access to the `isa` pointer (I don't actually remember if the `isa` pointer access was removed when Obj-C 2 was introduced or later when we got tagged pointers).
What the parent is likely referring to is APIs from the SDK, which do get deprecated, and then years later (many years later) removed.
Obj-C has changed a lot since I first used it. For instance, reference counting was performed manually via retain, release, and auto-release. There was a brief year where the Boehm garbage collector could be used, but then that was deprecated. Automatic Reference Counting (ARC) came a bit later and properties were added. For a few years you could mix manual reference counting and ARC. Early on you would override dealloc, but later that was a no no. And on it goes...
If you write Apple software, you are generally rewriting you apps every year. The API's are deprecated very often, and the languages are in constant flux as well.
Scott Meyers overlooks one problem with his quest to kill backwards compatibility: upgrading compilers is a no-go for many safety critical codebases. The re-certification of the code for released products would have to be repeated in its entirety - a sneaky bug or behavior change in the new compiler might introduce any number of issues. That isn't going to fly for cost reasons. This effectively freezes shared code between products at these ancient language standard levels.
> Just replace the use of ++ with an assignment from true.
You can't just replace it with assignment to true directly as postfix ++ evaluates to the unmodified value; you actually need to replace b++ with something like (b?true:(b=true,false)) to avoid breaking code that uses b++ in an expression. That seems significantly uglier than just allowing b++ to continue to exist though...
46 comments
[ 2.5 ms ] story [ 34.6 ms ] threadEDIT Docs about this: https://gcc.gnu.org/onlinedocs/cpp/System-Headers.html
[1] https://bugs.llvm.org/show_bug.cgi?id=22594
[2] https://bugs.documentfoundation.org/show_bug.cgi?id=39596#c3...
Just to play with it a bit. Unenforced coding standards can't be relied on. So you want something like lint (of old), tidy-clang, or git check-in hooks to help enforce. At that point it becomes tempting to say "if it is part of the language, it should be in the compiler." But back to your point- it is easier for small groups to enforce their own standards than to change the compiler for everyone.
I would think (or at least hope) that there are not many new projects being started in c++ these days. with this assumption, it seems like the main focus for c++ today should be on adding features that enable developers to incrementally rewrite old code with a view towards increased safety. range-based for is a great example of this. a large portion of unchecked vector accesses within loops can be trivially rewritten with range-based for to be much safer, and a small team can simply fix them one by one as they quash bugs.
on the other hand, removing NULL all at once in a legacy codebase could be almost impossible for a small team. I've seen many unfortunate instances where the code actually relies on NULL being the integer '0'. fixing this kind of thing across thousands of files would be an absolute nightmare.
I am certainly sympathetic to the idea that the code that will be broken by these types of changes is sloppy and should be rewritten anyway, but this is unlikely to actually happen. most resource-constrained teams are just going to freeze their projects at c++yy and never benefit from any new features.
edit: I partially retract this post. the gradual 10-year deprecation process he specifies seems reasonable enough. I still question whether making c++ less confusing to newcomers is a good use of resources. there's really not a lot of situations where it makes sense to start a new project in c++.
At least on Github it's growing : https://www.benfrederickson.com/ranking-programming-language...
I'm pretty sure that given the overall large increase in the amount of programmers, there are more new C++ projects being created this year than there were new software projects overall when c++98 was standardized. Consider that in the US alone, there were ~600k developers in 2002, and nowadays the estimates are at ~4.5 million.
I would imagine there are fewer new projects in C++ than, say, JavaScript, and fewer new projects in C++ than old projects in C++.
But C++ is absolutely still a live language! For the simple reason that there is no alternative which can work in all its significant niches (systems, realtime, embedded, HPC) and which is mature. Rust is on its way. D could be on its way. Ada never caught on widely, for some reason.
C++ caught on, because it came from AT&T and was embraced by C compiler vendors, thus landing in all OS SDKs.
Being part of a platform SDK is usually the path to fortune, for any language in platforms that manage to win widespread usage.
And a couple thousand lines of Turbo Pascal was 10 seconds! XD
I doubt there was any fall to the number of C++ projects started. For the domains C++ is used (OSes, premium apps the likes of Office, Photoshop, 3D, video editing, DAWs, etc, AAA games, networking, databases, number crunching, etc), there's no substitute with the same number of compilers, ecosystem, maturity, and programmer base. Rust doesn't even come close.
In the end it's really hard to force breaking changes for systems that are working sufficiently well. If I have something that I'm satisfied with (after all, I chose to use C++ over Go, c#, D, Ada, Pascal, etc., why not choose C++17 over some hypothethical incompatible C++22)
> That makes clang-tidy, if nothing else, a proof of concept.
More like a proof of failure. Apply clang-tidy's transformations to source code and now you've now got one gigantic merge conflict to resolve every time you merge from upstream. That's partially fixable if you script your integration, or your integrators have good checklist discipline (they don't) and apply clang-tidy to new upstream commits before trying to merge them, and you've properly documented that.
Downstream is more problematic. And in my experience, large merge conflicts like this are just begging for hard to spot bugs introduced by mismerging commits - much more common than I've noticed bugs from passing 0 to pointers or NULL to non-pointers. To add insult to injury, it'll fail to finish the job - for example, trivial edge cases like 0 being used in a macro which is interchangeably used to initialize ints and nullptrs depending on context - so now you need manual intervention to actually fix up the code enough to actually "break the egg".
Not to mention NULL in C headers, as mentioned in the blog comments, being not a great thing to get rid of.
> Experience shows that relying on compiler warnings to inform programmers about "bad" practices is not reliable.
Get a bigger CI build matrix. This is a criticism of the implementation, and perhaps those who don't use warnings-as-errors - they have much bigger problems than a confusing 0/NULL/nullptr trifecta though. Standardize some warnings? Sure! We've been adding things like [[nodiscard]] that, while still not requiring warnings, strongly encourage them to the point of being just a hair's breadth away from standardization.
Several compilers don't even like enabling new warnings by default - hence the -Wall -Wextra -Weffc++ -pedantic -etc -etc -etc dance, which still doesn't get everything you might want. If you want to change the culture around that so we opt out of warnings instead of opting in, sure, I'm on board with that. We already have the tooling to crank those up for your own code while using more permissive settings for third party code you'd rather not modify/break.
If you can't convince compiler vendors to warn more by default, you're going to have even less luck getting them to break code by default (unless you can trick them into thinking it's an optimization).
TL;DR: We've got more reasonable, less drastic tools. Maybe push those to be used more efficiently, instead of inviting a new Python 3 fiasco. I'm sure I'm not the only person who would jump to Rust (or Go, or Nim, or ...) instead of to C++vIncompatible - because if you're going to make a breaking change, why not break enough things to make it worthwhile?
Python 3 - fiasco or not - happened and went away. C++ fiasco is still ongoing with no end in sight - both on tooling side and language complexity side.
Bullshit. I'm still encountering actively maintained Python 2 codebases. Just to take one concrete example - Maya scripts, where AFAIK Python 3 still isn't an option. https://forums.autodesk.com/t5/maya-ideas/upgrade-to-python-... links http://www.vfxplatform.com/ which implies the Python 3 transition has been pushed back to 2020.
Maybe it's gone for you. Great, I'm happy for you. I'm still dealing with the aftermath of not having a clean incremental upgrade path, so you can see why I'm not in favor of adding more?
At work, we recently postponed a transition to C++17 due to library compatibility issues. Which is a shame - I'd really like to be using [[nodiscard]] for some APIs on MSVC (we're using vendor attributes on clang at least, but not everyone compiles with clang first.)
I'm sure you understand, then, why I'm hesitant to make upgrading even harder.
This has nothing to do with vendor refusing to upgrade.
We agree there's a lot rotten with C++. I have a large list of complaints about C++ that's been growing for well over a decade now, but that's just what makes suggestions like this doubly frustrating. There's so much wrong with C++ that could be fixed, and non-issues with serious consequences to their "fixes" like "I can still use NULL" come up, distract and waste developer time (meaning less time can be spent on actual issues with real consequences), that suggest wasting even more time fixing what isn't broken. It's like some compulsion to make old code look new and shiny at all costs, even if s/NULL/nullptr/ is about as effective as putting lipstick on a pig in that regard.
> This has nothing to do with vendor refusing to upgrade.
I'm confused as to how an upgrade roadmap is "refusing to upgrade". You can see some of the minimum patch version bumps they've required in the tables I linked. Despite the fact that it's going to break things and leave downstream on older versions until they get a chance to make the upgrade. I've done the downstream fixes for Maya plugins before (D3D9 -> D3D11 for plugins that hook into the renderer), I'll probably end up doing the fixes for Maya python scripts broken by the 2 -> 3 upgrade whenever that lands too.
The only way this is unrelated is if you live in a closed ecosystem where you have perfect control over your dependencies, no upstream or downstream to break compatability with, no branching to worry about, and a small or borderline inactive codebase where sweeping changes are trivial.
Most people I know who complain about the Python 3 transition are not heavy Python programmers.
Migrating to Python 3 was certainly a pain, but not really a major one. The number of developers who fled Python because of this is miniscule. If the Python 3 transition is the poster child of "things going wrong" with backward incompatible changes, I would heartily recommend other languages make those incompatible changes.
I believe that moving a 500k loc code base qualified us as semi-heavy. And relying on packages that didn't move qualified us as stuck.
Now - don't get me wrong: i/we liked python2. There was little wrong with the language or sticking with it. But please don't think the cost of migration was a weekend of lost coffees.
So while a one-way automated refactoring script sounds like a good idea, and is strictly better than just breaking backwards compatibility and expecting everyone to deal, it wasn't an unqualified success for Python.
[1]: https://docs.python.org/3/library/2to3.html [2]: https://pythonhosted.org/six/
In C++'s case, the transformation tool has much more information, so more things are possible to do.
E.g. let's take the ".erase" case from the article. In python, a method
can't simply change "remove" to "erase", because it has no idea what type "bar" has.A C++ tool sees
and can then safely change "remove" to "erase".Given
It's not so straightforward anymore.I honestly like Objective-C and prefer it, but I have been using Swift mostly for the iOS projects I have done in recent year or 2. Mostly out of curiosity though.
What the parent is likely referring to is APIs from the SDK, which do get deprecated, and then years later (many years later) removed.
Hey, class_poseAs was useful :(
If you write Apple software, you are generally rewriting you apps every year. The API's are deprecated very often, and the languages are in constant flux as well.
You can't just replace it with assignment to true directly as postfix ++ evaluates to the unmodified value; you actually need to replace b++ with something like (b?true:(b=true,false)) to avoid breaking code that uses b++ in an expression. That seems significantly uglier than just allowing b++ to continue to exist though...