I really wish there would be a linter (I realise it's probably a nearly impossible task) which would complain when you use legacy, unsafe language features.
As someone who doesn't work in C++ or have the benefit of 10 years experience to see the flaws, trying to write modern, safe C++ is essentially impossible. I spent a solid week trying to write something safe and only use C++14/17 features when they were available, and encountered a mountain of outdated- and mis-information about what one can and can't do, what is and isn't considered safe and why one certain feature is better than another.
It's nobody's fault that this happens, but with C++14 apparently fast becoming a language that is addressing it's #1 pitfall (safety) in an apparently very adequate way, it's frustrating that there's no "safe code" linter to stop rookies stepping on landmines.
Thanks for the list, it's a solid start, and the sibling comment about C++ Core Guidelines is another solid resource.
The introductory sentence gave me project-naming cancer:
> clang-tidy is a clang-based C++ “linter” tool.
Then why is it called tidy ??? It appears first on page three of google's search results for "C++ linter" in spite of the fact that anything from LLVM is probably a) current and b) of exceptional quality.
A little marketing-mindset would go a long, long way for these kinds of things.
Whilst the Ruby community lead by the example of DHH often takes this concept too far, it is inarguably effective.
That is what Microsoft introduced at CppCon 2015 alongside the C++ Core Guidelines.
Besides the clang-tidy, there is the ongoing efforts to improve VS analyzers, but I guess they will only be fully productized on VS "15", the upcoming release.
I also imagine other C++ linters are improving their C++ Core Guidelines support.
Under C++ Core Guidelines you are supposed to use [[unsafe]] annotation to mark such features.
Which is hella annoying. -Wall -Wextra is very needed, -Wconversion is nice but already borderline annoying, but enabling everything would just be a mess.
That's why you combine it with -Wno-... as appropriate on a per-project as well as per-file basis in addition to a simple way to disable warnings completely.
When using make, it could look something like this:
Am I the only one who uses C++ as C with classes? Sometimes I use vectors or strings and I like default values in functions and other minor improvements to C. I don't want to reimplement the n'th version of string concatenation when I can just use the "+" operator, sure... and there starts the rabbit hole. Before you know it you have a "protected abstract virtual base pure virtual private destructor" and have to explain the new hired mathematician who only has experience in R what the fuck you are doing.
I'd say unfortunately not. Focussing on the classes has the disadvantge it can quickly lead to 'everything is an object' or derived strict OOP mindsets thereby not only ignoring tons of other, more functional, goodies modern c++ has to offer but also leading to what you call 'protected abstract virtual base pure virtual private destructor'.
I use C++ mostly like "C with classes" and for me (a low-level game programmer) it's close to ideal. It absolutely baffles me that there is not yet a language that's explicitly a thoughtfully-designed "C with classes".
No, you aren't. I've also seen (and done) C++ used as C with classes in embedded systems development, where you really need to be sure that the compiler isn't doing something you don't expect.
Disagree. C++ has the philosophy of "You don't pay for what you don't use". Just use the parts that help with your problem. If your problem grows and you need more, you aren't trapped - the language has more. But if you don't need it, don't use it.
For that matter, I'd argue that this is a reasonable approach for every language.
I completely disagree. C++ was not created to extend or enhance C; its an entirely new language providing backwards compatability only for legacy reasons. Using C in C++ introduces deficiencies and dangers that C++ was designed to overcome. As a C++ developer I come across a lot of code where people still use things like FILE* and close the handle in a goto. That should be frowned upon, there is no advantage for this method vs. using a stream; which handles the file handle while being scope bounded. Promoting the use of C in C++ is something terrible misguided and plain wrong.
This made me think of the passage below from Edsger Dijkstra's ACM Turing Lecture from 1972. Back then there was no C++.
"I remember from a symposium on higher level programming language a lecture given in defense of PL/1 by a man who described himself as one of its devoted users. But within a one-hour lecture in praise of PL/1. he managed to ask for the addition of about fifty new “features”, little supposing that the main source of his problems could very well be that it contained already far too many “features”. The speaker displayed all the depressing symptoms of addiction, reduced as he was to the state of mental stagnation in which he could only ask for more, more, more..."
And every time there was a language designed against PL/I like languages, with the goal of fighting complexity, its adoption by the industry lead to feature growth and becoming just as complex, usually with solutions hindering by backwards compatibility.
Yes C++ is complex, but so are Python, Ruby, Ada, Fortran, C#, F#, Haskell, OCaml, Java...
Even Go will get caught in the complexity game if it gets enterprise adoption at scale.
The big difference here is how additions in C++ tend to work - e.g. keeping all of the deprecated ill-defined legacy and growning features on it like tumors until there are no more symbols left. Unlike Ada and Python which aren't afraid of throwing away poor design and were overall more thought out in the first place (especially Ada).
Its not a "complexity game" in so much as poor design being over-compensated for. C++ is like cancer infecting the minds of young programmers with buggy habits -- and no amount of features and static analysis will change what lies beneath... :p
>Also Python is the poster child of what happens when you throw compatibility away.
And what, exactly, happened?
For years I avoided Python3. Updating my code base was a hassle I did not want to deal with.
Finally, a few months ago, I had some spare time and took the dive.
And nothing bad happened. I did not even spend hours on it. At this point, all the libraries I need exist for Python3, and the automated tools update my code for Python3 without manual intervention almost every time.
>Of a community dragging their feets while avoiding to upgrade at all costs, with developers being forced to backport features into the 2.x branch.
A minor problem compared to dealing with developers continually using poor paradigms for eternity because C++ did not want to break compatibility.
And I believe the developers who backport to 2.x are not those who implement the features in 3.x. The latter don't care at all about 2.x. Those who backport do not see it as a "pain" but as a new feature to add to their language.
It's amazing that there's someone out there thinking that Python's compatibility break is a "minor problem", even when comparing apples to oranges.
Fortunately the architects of the change said that they've learned their lesson. They don't have much choice either, another one like this and it would be bye bye python.
What I meant to emphasize was that Ada was well designed in the first place, and yes GC was a problem and so were some of the restrictions and aspects of the standard libraries. For example, a big one was unconstrained types for generic actuals...
C is a mine-field of devastating design flaws which have caused many people to die because of decades old decisions made on a whim and any change to basic libraries to make them safer and removing dangerous functions is heresy.
As far as Python, yes the two versions of the language is troublesome for users but the language is objectively better and students learning programming for the first time benefit from a more robust version.
There are so many parts of C that are unsafe that a secondary tool is needed to have an reasonable type-checking and that tends to be devastating if they can be easily avoided by even safety critical engineers.
And honestly I dont think we agree on what "a few" is. In my book if any more than 4 or 10 people die from a solved problem in computer science (like strong typing, mutexes, and range checking) that is already way too yes many
As far as decisions on a whim compare the two language design efforts and i'll let you decide:
"...despite the changes that it has undergone since its first published description, which was admittedly informal and incomplete..." ~ Dennis M. Ritchie
It took a decade to even decide what the C language really was and standardize it -- sounds pretty undefined and whimsical to me. But we all use and understand words differently so let's agree to disagree :)
I fully agree with you regarding C, but even though C++ happens to be copy-paste compatible with it, C++ isn't C.
It does provide the necessary language features for security conscious developers to write safe code, the fact that many write C++ as if it was "C with C++ compiler" is an unfortunate one.
Yes it would have been great that we had Ada instead of C++, sadly that wasn't what greedy Ada compiler vendors wanted us to have.
I won't necessary call out Java as a complex language. However in not being so complex a language it sacrifices a lot of expressiveness found in other languages.
C++11 and C++14 made me start to like C++. The build workflow is still horrible and cumbersome but at least the language itself has become nice to use.
Agreed. The template stuff blows me away, feels completely foreign to me. I'm barely catching up to C++11's features and looking at the '14/'17 stuff gives me that feeling of being assigned a ton of homework.
The one feature that really annoys me is the std::optional. This is awesome and very needed feature however it is too clunky for something that should be used very frequently. Swift does such a nice job with its '?' operator, I wish C++ had something similar.
I really wish a group of really smart dev get together and come up with a new language based just on the modern C++. Perhaps even call it MC++ (Modern C++). Make it's syntax as simple and easy to learn as Python and yet give us the performance close to the compiled C++.
I'd take that knowing very well that I can't do all the powerful stuff I could with C, yet I have a safe and idiot-proof language to work with in my hands.
To replace C++ it you would either have to make a near human quality automated converter (which is likely impossible right now) or make it compatiable with C++, in the way Groovy is compatiable with java.
A better example is the way C++ was compatible with C when it first came out. Apache Groovy has lots of little incompatibilities with Java, e.g. == has a different meaning in many cases.
Nim is closer to that ideal than Rust, I think; Rust requires provable object ownership that doesn't go bad, Nim uses an (optional, but strongly suggested) GC.
Nim's syntax is mostly pythonic, and it's metaproramming language is Nim (unlike C++'s abominable template metaprogramming language).
A very heavily biased rookie response. Not trying to be snarky.
Rust would be an obvious choice for what I described. It's been on my personal list for a while to learn Rust and make use of it. I think I will pretty soon.
I've been demotivated (to start) by reading over here on HN or elsewhere about how much of a learning curve it is to learn Rust. Perhaps, it was the bias that I already know what C++ was like in terms of syntax and idioms that made me ask for a choice with least friction.
> I've been demotivated (to start) by reading over here on HN or elsewhere about how much of a learning curve it is to learn Rust.
That learning curve is necessary for safety. If you want a safe C++-like language without Rust's learning curve, you either (1) have a brilliant solution nobody has come up with yet or (2) don't actually want a safe language after all.
Nice summary! As someone who writes multi-platform C++, it would would be even greater (but a lot more work) if each feature listed which version of each major compiler introduced support. (ie. Can I use this feature if my codebase is currently compiling under given versions of Clang, GCC, VS.)
Is there a similar list for linters, analyzers and editors?
I've been in the situation many times where the compiler knows about a feature but the auto complete doesn't and the static analyzer will totally fail early and not report anything else except syntax error.
Most features are very good. My favorite ones are range-based loops, lambdas, and strongly-typed enums.
The things I dislike most are pairs and tuples. They make the code enormously harder to read, understand and debug, compared to non-standard classes or structures with meaningful member names. Even this guide promotes them in “using Coordinate = std::pair<int, int>;” Please, never do that, create your own class with x/y or latitude/longitude instead.
Sometimes "using Coordinate = std::pair<int, int>;" does have upsides, though. One example would be when using a serialisation library that knows how to handle pairs. In that case you don't have to add (de-)serialisation code to every new class. It's also nice to be able to use std::tie for unpacking: "std::tie(x, y) = get_coords(blah);"
If you use the members a lot, a struct with named members really is much easier to read, though.
Sometimes all the meaning is in the name of a thing (or in the name of a function returning such a thing) and member names dont help but hurt. x/y is a good example, why not a/b? I prefer not having to make these decisions. Also tuple assignment syntax is very nice from a usability standpoint (I don't think C++ has it, but e.g. Python has).
The author named their pair "Coordinate". In math and in computer graphics there’s widely known convention the fields of Cartesian coordinates are named x/y and not a/b.
When you’ll start writing code that use and/or modify those Coordinate values, meaningful names in C++ source and in the debugger help a lot.
It is worth to note that template-related features make compilation time significantly longer. It might seem no-problem unless you face it in a bigger team, then these extra seconds (or minutes) are multiplied.
As someone who doesn't work in C++ or have the benefit of 10 years experience to see the flaws, trying to write modern, safe C++ is essentially impossible. I spent a solid week trying to write something safe and only use C++14/17 features when they were available, and encountered a mountain of outdated- and mis-information about what one can and can't do, what is and isn't considered safe and why one certain feature is better than another.
It's nobody's fault that this happens, but with C++14 apparently fast becoming a language that is addressing it's #1 pitfall (safety) in an apparently very adequate way, it's frustrating that there's no "safe code" linter to stop rookies stepping on landmines.
Thanks for the list, it's a solid start, and the sibling comment about C++ Core Guidelines is another solid resource.