Convincing C programmers to switch to C++: A look at human behavior (2016)
blog.kareldonk.com
blog.kareldonk.com
And I'm not here to argue how terrible C++ is (I've done enough of that elsewhere), but only that "behavioral" arguments cut both ways, and are usually little more than an ad hominem attack and/or some good old marketing tricks rebranded as "behavioral science."
Haha that's one way to put it :p
For those new to this debate: Yosef Kreinin is the author of the (in)famous C++ Frequently Questioned Answers.[0] it's quite a body of work. Speaking of which: thanks for writing it, Yosef. I greatly enjoyed reading it back in the day, and it had a big impact on young me.
It's especially funny to watch people on both sides of whatever issue argue that the side they're opposed to is in a self-reinforcing bubble that only closes them to the beliefs of their team, which are obviously correct. But, the thought process that produces the belief that their team is correct is incubated in exactly the same sort of bubble that they're complaining about.
It really doesn't matter if C++ is better or not. The article doesn't really even try to talk much about that at all. No matter what C++ may do, what it may change, what it may improve, how it may perform, how it can be simplified; it's almost impossible to convince C programmers to try C++ (or golang, or Rust, or D).
The article really is about how it's almost impossible to change someone's mind on any topic. Anyone who likes to engage in internet discussions is well aware of the phenomenon.
> the fundamental energy that underlies and is responsible for the universe is consciousness. So consciousness is inherently logical.
> Since humans are a part of the universe ... humans are also logical or rational by nature.
> We’re born with the need for sexual satisfaction, yet society teaches us ... to suppress and even repress our sexuality. This is one of the most important seeds for irrational thinking that gets planted into our minds.
There's enough pseudo-scientific bullshit on the rest of this person's site that I'm very wary of drawing any conclusions from this article.
That's not true; they are mentioned several times in the first big bullet list. Also the Dan Saks talk he discusses several times throughout the article is specifically about talking to C programmers about C++.
But regardless of whether he is speaking about something specific (C vs. C++) or in the abstract (rational vs. irrational people), he is making the same flawed presumption: that certain choices (like C++) are unquestionably better than other choices (like C), and that if people can't see this then the only possible explanation is some kind of cognitive impairment.
The whole argument presumes that the author is smarter and more rational than other people. He might not even realize he is doing this, but other people can most definitely pick up on it.
Aha, so that's why everyone is posting comments about how terrible C++ is. The author is coming across like an ass, so we must attack that which he appears to be defending: C++.
I don't really pick up on the bad attitude (probably because I have it too), and I don't really care that much to defend C++ or C. I went through the article, noted a few references to whatever psychological studies were there, and decided to read those later. I don't really care if C or C++ is "better". I barely use either anymore.
- Learning to use a new system effectively takes time and energy. Are you 100% sure that the benefit of the new system is great enough to offset these costs?
- Hybrid codebases have higher maintenance costs than homogeneous ones. If Kiwi mixes with Strawberry seamlessly, maybe that burden is lower—but the more true that is, the harder it is to believe that moving to Kiwi confers a large advantage.
In this specific case, I could believe that C++ by seasoned C++ users leads to demonstrable net gains. But it's easier for me to believe that switching to Rust or Haskell would confer higher gains, corresponding to the higher risk and higher cost of switching. So I think it's not that people are irrational about avoiding C++. I think that C++ is in an awkward place on the hill between C and things better than C++. If you need something better, you will go to something with better tradeoffs than C++; if you don't need something better, you just live with your existing C codebase.
I'll also add QString, AnsiString, BSTR and glib::ustring to the mix :)
I mean, maybe the actual details of the case for switching are slightly beyond the scope the author intended to write about, but simply starting with an assertion that "modern = better, therefore people should have already switched if they were rational" and treating that as self-evident strikes me as highly arrogant and logically fallacious.
Unless... they didn't actually think that much about the topic. I dunno. I didn't watch the video so I don't know if it's in there.
C++ is more complex, because it covers more concepts. But when you get simple safe and to reusable things from that complex the difficulty is reduced.
What is the right way to store and unknown amount of things in C?
There are about a million ways to do and every project will implement their and about half will work. Of that half maybe 1 in 10 will have an API that is intuitive to the reader, and depending on the reader that 1 in 10 will be different. Now what if what you an associative container instead?
With C++ just using std::vector, because this is a solved. (or map/unordered map for the associative container).
This continues on with libraries. Every API needs to have a large series of questions answered every time you pass a pointer. Because C has no concept of ownership who is supposed to delete it? Without const references extra caution to distinguish const pointers and pointers to const things, why is this important? Without templates writing an API that works on multiple types involves dealing with void* at run time, presuming you don't want to actually use anything in the data.
C looks simpler because it is smaller. C++ is easier and simpler because it has already dealt with many of the hard problems.
C simplicity is real. It makes it easy to write compilers. Compare with the enormous complexity of writing a C++ compiler. This is actually quite important as any software development needs tools. Writing tools for simple languages is easier. Writing tools for C++ is next to impossible. Most of my C++ career I have never had proper refactoring tools. I haven't even been able to use a lot of C++ features because it has taken so many years for all compiler writers to implement all the features.
I can't think of a single other language where it has been so many years of lag between a language specification and it being widely adopted among major compilers.
The simplicity of C makes it easy to interface C with a huge number of other languages. C++ can't interface with almost anything. It is just way too complex.
A much saner superset of C, is Objective-C which can actually interface very easily with other languages.
I will respond to your points in the spirit of open exchange anyway, but if you continue to be rude it will just shine a poor light on C programmers as a whole. Since I feel you ideas are lacking factually this might seem like an attack, it is not an attack and I even ask for more information on points with merit.
I have pointed out that elsewhere in this thread that the standardized C ABI is perhaps the only thing I like about it. C++ can seamlessly use this, but not by default (which is a weakness of C++). So anything C inter-operates with C++ can too. So your point that C++ inter-operates with less is entirely without merit. Using this I have interoperated with Lua and Ruby from C++, it works well.
To push interop further there are several tools like SWIG that seek to allow exchange of rich objects between languages (rich objects that C doesn't even have), and these tools work. I have written code that throws exceptions from Java an catches them in C++ (and vice versa of course) and things of similar complexity in a few other languages.
It feels fantastic to have low or 0 cost abstraction around passing complex objects between systems and have all the code that does that strongly checked at compile time (And covered in Unit tests too that but that could be done in C too, I just don't see it often).
As for tooling, I again think your points are largely without merit. The are plenty of tools for both languages and there are plenty of simpler languages with less tools. It seems to me that the amount of tooling is not related to complexity but rather popularity of the language.
A language that is functionally driven by one vendor and supplanted by that vendor with a newer language (swift) is not a reasonable solution to most problems. I am curious about we makes it interop better than interop with C++, what does it do right that C++ does wrong?
Hey now, most of us have nothing in particular to do with this guy!
The first statement is arguable and the parenthetical statement is false. C99/C11 have language features that C++ hasn't adopted, which makes it somewhat obnoxious to support C++ from C codebases that use them. One example is the "static" keyword used in array parameters.
But according to OP, it's not C++ that's irrational, it's the programmers who don't want to use C++.
[0] https://twitter.com/sigfpe/status/857748171778252800 [EDIT: corrected broken link]
- In C "getchar" returns... an int.
- Pointers and array are kinda the same thing, but not exactly. The rules for when an array decays into a pointer are sometimes unintuitive and surprising.
- Same thing for the implicit integer types promotions.
- `char *s = "foo"` is not at all the same thing as `char s[] = "foo"`. Arguably the former should be considered erroneous, but compiles just fine in C. G++ gives a warning for the same code however.
- There's also the ridiculous "gets" function that's so poorly designed it could be part of PHP. This one finally got officially deprecated though.
Of course many of these issues are also part of C++ since it's mostly a superset of C but in general it's stricter and more strongly typed.
> decltype(auto) f1(){int x = 0; return x;}
> decltype(auto) f2(){int x = 0; return (x);}
> Latter, not former, returns reference to int.
- Show them how classes makes things easier (automatic object management, some operator overloading, etc)
- Show how the STL makes most things easier (arrays, maps, etc)
How not to convince them:
- Show uses of excessive/pathological inheritance
- Use of templating beyond the basics
- Insist they use C++ functions for every single thing
- Insist they OOify every interface in their code
- Creating giant classes (structs) with a getter and setter for every field with no control or validation
- Going crazy with operator overloading
The problem with the STL is that you are always running into roadblocks when you try to compose things. I tried for a very long time to like the STL, and in the end it was very very good for one thing -- pushing me to look for something better.
I suspect things have improved some with the newer C++ standards (it's probably been almost 10 years since I gave up doing much of what I wanted to do in C++), but I much prefer Lisp, Scheme, and other languages now (most, if not all of them dynamically typed). Learning Lisp-family languages did indeed change how I program in other languages -- IMHO greatly improving the way I write code.
I might revisit C++ at some point, just to see what's happening there. I've only skimmed a few articles about the newer standards, and some things look promising. But it would probably take my involvement in a real-world project that uses C++ to get me to go there. I've just spent way too many frustrating hours trying to get things to work the way I wanted in C++.
I really can't see what C++ has to offer anybody. It is a horribly complex language, which doesn't interface with anything except C.
My experience is that I like writing code that uses operator overloading, but hate reading code that has it. Kind of like programming in Perl. In both cases, I find that on large projects, it is best to avoid the technology.
In this situation, C is a much better choice because most other languages have nice interoperability with C, but seldom, if ever, with C++. For example, as an iOS developer I can use C and C-libraries very easy with Swift, while inter opt with C++ is not possible at all and probably never will.
The main thing keeping me away from C++ is that it does not have a stable common ABI. This makes it very nearly impossible to use C++ to create and distribute a shared library. I even believe Google developers internally are prohibited from creating C++ libraries for this reason. So I'm sticking with C for low level stuff. It's a perfect glue language and fast. For higher level stuff, why use C++, when you can use Swift, Java, Haskell etc etc?
Disclaimer: I don't love C++, I think it has lots of problems, but saying C++ is wrong, while C is right suggests to me that lots of people didn't take time to actually learn C++ but have strong opinions on it.
You can get nominal typing in C by wrapping your primitives in single-element structs. Slight syntactic overhead, no runtime overhead. In my C code, I try to avoid passing primitives between functions. It worked out well on my last large C project.
But according to TFA, people who prefer C are just being emotional and irrational.
[0] Scott Meyers. Things that Matter - DConf2017 [@27:51] (https://youtu.be/RT46MpK39rQ?t=27m51s)
With C++ it easier to express higher level concepts. I can have a map of strings to some class instance. Then I can use some string to lookup class instances. There are simple idiomatic ways to do this. They are short to writes (<10 lines), they will have decent performance and will be low on bugs and clear ownership semantics.
With C it is common to have an array of pointer to pointer to void pointers. To get associative lookup it might be even worse and have functions that need to pointer to pointers, with who knows what ownership model and what idioms in use.
- Easier to write code generators for: I use libclang to read in annotations that will generate new code according to where the annotations are being used. If I have to take care of every edge case and new features added to the latest C++ standard it would make the code generator more complex.
- Using plain old data structures: My code generator generates new code to be able to work with the plain old data structures which data can be interleaved or non-interleaved using data-oriented design. Classes will not add that much value.
- C compilers are easier to write: I integrated the tiny C compiler inside my program to be able to compile C code on demand. The C code can then use the code I've already written.
- No name mangling by default: I dynamically load a lot of plugins and do not want to bother with binary incompatibilities all the time (if compiled by different compilers like the tiny C compiler for ex.).
- I mostly use libraries written in C
- Low-level access
If I need concepts or meta-programming etc. I can already use Nim or write my own code generator, else I would rather choose something different than C++.
To be more on-topic. Confirmation bias. On The Internet you can find confirmation of something being true about almost every topic. Whatever people believe is the truth, it will not change the reality. Which programming languages are better is a very difficult thing to measure because there are many factors to consider. Being used to a certain programming language can be a good reason not to change.
https://en.wikipedia.org/wiki/Confirmation_bias
Update: added some explanations, and more on-topic
1) By using libclang to parse your own annotations you're kind of using your own fork of C language, not the standard one. You can't really bring your annotation parsing engine to some company to work on an existing C project,
2) C++ also uses plain old data structures, using 'class' does not magically introduce any overhead in structures, unless you start using virtual functions, but nothing forces you to do it,
3) I think that by stripping name mangling you actually increase binary incompatibility, because without mangling you can't know what ABI was the function compiled against. Which compiler was it? What are the arguments? Is it MS ABI or UNIX ABI? Nobody knows for sure even if it seems to work correctly for some set of arguments. Disabling mangling sure is convinient at the beginning, but brings problems and incompatibilities at later stage.
4) Given that Windows or macOS kernel drivers are written in C++ (more or less), low level access is possible in C++ as well.
What I meant is that C++ does not add anything for me personally.
POD-structures are all I need and the way I fetch/store the data may require the struct layout to be interleaved or non-interleaved (depending on the platform / architecture I am targeting for a specific build) requiring different code to be generated to access them.
I do not need to disable name mangling or add 'extern "C"' everywhere (I still do in case the code will be used from C++) when I just use plain C.
I like the many new features added to C++ like concepts, lambdas etc. but for these I prefer to use Nim (they just added complete concept support as well).
I still vastly prefer C++ over C though :P
And sometimes you make seemingly illogical decisions that end up being objectively worse decisions. The problem is that we don't really have a way to quantify our emotions usefully, which means we can use them accurately and are forced to allow for enormous amounts of error in our calculations when we provide any level of significance to them. That's why they are often seen as detrimental to rational decisions, not because they don't matter (obviously emotions do), but because including them sometimes leaves us no better off than flipping a coin (are the downsides really that bad, or is your fear of change in this instance vastly overwhelming the other considerations, and in an unwarranted way that you aren't entirely aware of?).
If that theory is true (not sure, I literally just learned about it this morning[1]), your emotions do have weight in something like this, but it's filtered through multiple lossy abstractions and has a propensity for false positives. That's a much less rosy interpretation of how useful they are, and if true, means we might be far better off trying to cultivate a better understanding of the nuances that are causing those reactions and assessing them rationally (to the degree possible) than to using the lossy abstraction itself with any significant weight.
1: http://www.pc.rhul.ac.uk/sites/lab/index.php/research-themes...
To think you understood everything before you started and insist on sticking to that after you find it's not working out isn't rational, it's stubborn.
Why on earth should a C developer chose C++, when they could chose Go, Rust, Swift and Nim instead? And if you really insist on an old language I'd rather use Objective-C than C++.
Only reason to ever pick C++ is that you got a sizable existing legacy C++ codebase. That is why I am stuck on C++.
A C developer by definition doesn't have legacy C++ code to deal with so there is no reason to pick C++.
Saying C has no benefits over C++ is rather ignorant. Complexity has a real cost. For most of my C++ career that has been reflected in an utter lack of functional tools for manipulating C++ code, e.g. doing refactoring. Refactoring C code is a lot easier, as a regexp search and replace is far more dependable, since there is no function overloading.
While this happens, it's also an empty argument that can be applied to everything.
How about the author there misunderstands his own data on C++ because it challenges his preexisting beliefs (that C++ is "de facto" better)?
It goes downhill from there fast, to argue that those pesky people who dare to not want to use C++ are irattional, conditioned from childhood, etc (those willing to use C++ are not, because of course C++ is the only reasonable choice a programmer can ever make between C and C++).
>In fact, Saks found that quite often logic, facts and the truth were simply not sufficient enough to convince people. Instead, people reacted in a very irrational and emotional way, and kept sticking to and defending their beliefs. People’s basic reaction was “show me all the data you want, C++ is still undesirable.”
The problem in the paper is that some BS arguments and numerical data in favor of C++ (which I'm assuming they have -- they fail to mention any of them in this article) are conflated for "THE truth".
Sorry, author, but you are not showing people "THE reality", you're showing them some arguments and some numbers.
The programmers you are talking to (those that have tried both C and C++) are the ones that have actual empirical experience from actual reality on what C++ gets them -- and whether its worth the tradeoffs they've seen.
For one, there's an ergonomic factor in language and API design (it's usability) which can be highly subjective -- and syntax/api usability is one of the big reasons people dislike C++. This issue cannot be shot down with any "objective" argument or numbers table....
Because they themselves derived some benefit from it, and believe the other party would too, if only they would try it.
Sometimes, I don't think it's just benefits, but certain languages offer different ways of doing things that other languages really could benefit from. Our older languages teach us things as we use them, like that nullable pointers as our only reference type were a bad idea. Encouraging others to use languages that adopt different ideals would seem to be to just be people trying to get people to see the merits of those ideals.
> Why get into religious wars?
Because we're still using languages with nullable pointers. More seriously, because people care about the quality of their work, and you don't always get to pick the tool for the job. And it can very well be that there isn't a good tool for the job, but only and okay tool for the job: while I use Python extensively at my job, and while its speed of development definitely benefits my team, I would kill for some static typing. (I've been looking into mypy for this reason, but being on Python 3 would help…)
And people don't always use the right tool for the job, or I'd be done trying to explain why they should not be using raw bytestrings for text. They didn't pick the wrong tool for the job — they simply don't understand that actual string types exist, or why they should use them. (It doesn't help when the language/library's obvious choice is the wrong choice.)
I don't want to maintain a giant heap of buggy C Code.
I don't want to deal with bugs in the JVM/JNI.
I want ownership semantics expressed in code. When a C functions accepts or return a pointer who deletes it?
I want code to be easily tested, automatically. Common C code has so much shared mutable state that unit tests are rare, and when used are trumpeted as masterworks of engineering like the sqllite test suite.
C makes all these things hard or impossible to work with. From my perspective, the only positive it brings in the standardized ABI.
Though, Keeping thIngs Simply Stupid, is really the only lesson one has to know/learn. When C++ has a specific function go with C++, when C is sufficient use C. If a bash script is sufficient use that.
If people could just show why something is cool in what situation, instead of why something should be used over something else. And this includes guides 'how to switch desktop OS' too.
Each side of the argument have their own set of premises/axioms to come to certain conclusions but there are always unknown truths which people tend to ignore. if there are no unknown truths then the argument should be contradictory
I could talk to my perl programming colleagues for days about the advantages of python over perl, but what got them to switch was boto, since we were moving to aws.
“If you’re arguing, you’re losing.” — Mike Thomas
No, no, no.A shouting match doesn't help anybody. A civilized exchange of arguments does. And the establishment of evaluation criteria is a very good basis for listening to the other.
The not-arguing approach often times results in "let me show the merits of my technology without listening to your requirements / evaluation criteria".
C is different from C++ because it targets different use cases. So it needs to be evaluation in the context of use cases. End of story.
If the fastest one took 100s, then the one taking x1.57 took 157s.
I shouldn't have made either of these posts.
C# is more what Java should have been (which lines up pretty well with the history of C#).
You start criticizing people for not believing you when you have one example comparing two different programs implementing an unspecified task on an unspecified compiler. This is ridiculous.
I mean, for crying out loud, your headlining video is a talk by a person who admits that he hasn't done the thing he's trying to convince people to do.
He says things like this:
"You don't want to wait for the market to take care of this, you would like to take some proactive steps to be able to make more of the people who should be using C++ willing to use it."
in the context of aerospace, which clearly he has no authority to speak on, since he misses one of the fundamental reasons why C++ is not popular or even acceptable in much of aerospace: implicit allocation. Implicit allocation is incredibly dangerous for high assurance systems. You really need to know exactly how much memory can be allocated, when, and what state the exact allocations will put the allocator in. C++ has some facilities to manage this, but man, it is easy to drop a plane from the sky by assuming that your allocation did what you wanted instead of verifying it.
I'm writing this mostly as a plug for DJB's proposal for a "boring" C compiler: https://groups.google.com/forum/m/#!msg/boring-crypto/48qa1k...