
Should C Programmers Learn C++, Go or Rust? (2018) - WoodenChair
https://ds9a.nl/articles/posts/cpp-rust-go/
======
pcwalton
The entire Rust section is premised on the common fallacy that "bad
programmers", however defined, are responsible for the safety and security
problems of C and C++. The conclusion is that, because "bad programmers" are
supposedly incapable of learning Rust anyway, Rust's safety features are
pointless.

None of that is true. The biggest memory safety flaws that have caused the
most damage have been, more often than not, written by the _best_ C and C++
programmers. That's because the best programmers are the ones who write the
critical C and C++ code--Chromium, Firefox, WebKit, the Linux kernel, nginx,
libpng, libjpeg, libc, etc. "Bad programmers" (whatever that means) can't, and
don't, usefully contribute to projects like WebKit to begin with.

The problem is with the tool. Though it's an inconvenient fact to accept,
humans have shown themselves incapable of writing safe C and C++ code at scale
using standard software development practices (i.e. not spending 10x on
verification). That C and C++ are due to be replaced shouldn't really be
controversial--it's natural to expect that we know how to design languages
better now than we did in 1978.

~~~
ncmncm
Equating C and C++ must seem compelling when one is exposed to C++ as it is
written at Mozilla and at Google. Both places enforce coding standards that
require programming under what amount to 1990s conventions, with a few modern
tricks added. The consequence is that you get few of the benefits of modern
C++, but all the costs.

Google and Mozilla might never get out from under their burden of enforced bad
coding habits. It is a mistake to attribute to a language the flaws of one's
corporate culture.

C++ is not at all under threat of being replaced. The number of C++
programmers is increasing at a much greater rate than of Rust programmers, and
the language is evolving quite rapidly after its stagnation in the '00s. If
you learned C++ before you could use C++11, you will be surprised at how much
more fun C++ is now. Coding C++20 will be even more fun.

~~~
pcwalton
> Equating C and C++ must seem compelling when one is exposed to C++ as it is
> written at Mozilla and at Google. Both places enforce coding standards that
> require programming under what amount to 1990s conventions, with a few
> modern tricks added. The consequence is that you get few of the benefits of
> modern C++, but all the costs.

That's just not true. Both organizations use "modern C++" everywhere. The new
C++ proposals tend to come from large companies such as Google, after all.

People tend to assume that every new release of C++ will automatically solve
all the problems with the previous releases until proven otherwise. This has
always mystified me. Nobody has demonstrated that any new version of C++ has
been able to stem the flood of memory safety problems.

It's interesting that few people can actually articulate _why_ modern C++
supposedly solves the memory safety issues, other than just mentioning smart
pointers. Smart pointers actually do very little--shared_ptr can bump
reference counts _sometimes_ and that's about it--and what little benefit
comes from smart pointers is generally outweighed by all the new ways to get
use-after-free in modern C++. Free happens invisibly in subtle places in
modern C++, while in C free happens explicitly when you write "free()", which
tends to be safer. In my opinion, modern C++ is significantly _less_ safe than
classic C++, which is in turn significantly less safe than C.

~~~
ncmncm
I am forced to conclude, from your complaints about the C++ code that you are
exposed to, that it is very, very far from modern, for what I have to assume
to be corporate reasons.

I don't know why you carry on about smart pointers. I find I use unique_ptr
here and there (shared_ptr, practically never), and never, ever in any
interface. Instead, modern C++ code traffics in value types, and relies on
destructors, almost always from a library or compiler-generated, for cleanup.
Use-after-free never happens because anything freed was only ever referenced
from within a value-typed object that no longer exists.

The reason that, in modern C++, memory safety issues fade into insignificance
is that we have access to libraries that are fully as fast as we could ever
code in-line, optimized as only code that is used in many places can afford to
be, that encode logic correctly, once, that can be used everywhere without
compromise.

Rust does not yet have the facilities to capture as much semantics in
libraries. Anything Rust can't capture in a library has to be coded in place,
with all the opportunities for mistakes that brings.

So, Rust is good at safing low-level memory fiddling that we just don't do
much of, anymore, in C++. Meanwhile, we avoid myriad errors that come from
relying on necessarily leaky abstractions.

~~~
xiphias2
I was also using unique_ptr at Google (shared_ptr is not encouraged), but the
problem with unique_ptr is that it doesn't solve the more complex data
ownership cases, and it's totally unusable for multi-threaded data race
problems.

Rust Rayon is a huge difference from anything available from C++, and it can't
be solved in C++ without adding borrow checker to the C++ language (which
wouldn't be a bad thing to do in my opinion, it would help modernizing old
code bases).

~~~
ncmncm
When you have complicated ownership cases, you have a fundamental design
problem. The Standard Library is not a place to find patches for those.

Likewise, multi-threaded race problems.

~~~
xiphias2
You can't use unique_ptr for everything if you want to have performant code.
It needs heap allocation, which slows down the code base compared to stack
allocated variables, in which case tracking the ownership is much more
complex, but it's worth it, especially if you have millions of users.

------
swsieber
> The people writing unsafe C today will not embrace Rust simply because it
> does not make their life any easier or more fun. If they were willing to do
> hard work, their C code would not be as unsafe as it is.

I feel like Rust has expanded pie for c-level performance languages. For
system languages. I'm not comfortable writing C or C++ - if I miss something,
it means UB. I am comfortable writing Rust - it generally yells at me if I
were to trigger UB (modulo unsafe, which I stay away from).

Edit: Though I have to admit, my point doesn't apply to the article. He's only
talking to 'C' programmers in the article.

~~~
unrealhoang
This reason exactly, when I was learning Rust I had a milestone of complete -
when I can reason the errors reported by the compiler, and comfortablely make
my program compile. At that point, I could already let my program to run on
production. Whereas in C/C++, when learning, there's always the fear of
missing something, and without a C/C++ veteran in team to review, I would
never trust my C/C++ program to run on production settings. All that is to
say, Rust opened a whole new way (better for myself, YMMV) to access low-level
programming for higher-level language programmers.

~~~
nazka
This is a huge selling point for Rust. If you have a project done in C++ you
will need to have at least one amazing developer in your team to double check
all the code to insure that nothing can go wrong. You will also preferably
have a team of developers that are medium+ in coding in C++ because if it’s a
junior team the senior dev will spend all his time teaching and correcting the
code his team does.

With Rust thanks to the borrow checker and all the help from the compiler you
won’t need that wizard in your team. That means less stress thanks to the
compiler and less management and you can have a team with a lot of junior devs
without having the necessity to have anybody to be senior to oversee the code
and you can still be confident to ship code to production.

------
yawaramin
I'd actually recommend D ( [https://dlang.org/](https://dlang.org/) ) or OCaml
( [http://ocaml.org/](http://ocaml.org/) ) over any of those.

\- D is a safer, cleaner, more convenient version of C++. It has a Rust-like
build system/package manager (dub), a sane module system, Rust-like unit tests
available anywhere, C++-like compile-time expressions and functions, C++-like
generics, and contract-style programming (which C++ is also about to get) for
safer code. Oh, and the D compiler is known to be fast, unlike C++ and Rust.

\- OCaml is a pragmatic functional programming language focusing on a sound
static type system with strong modules support, rather than on total purity.
It too has a fast compiler and targets JS as well as native.

------
krupan
I'm a fairly seasoned C programmer. I actually started with C++ back in the
last century, but when I had the chance to do plain C I quickly saw it's
benefits over C++ (at least back then). I have long pined for a better
language that could be used for embedded systems programming.

In my current job I am now using C++14/17 (not my choice). I'm starting to
like auto, but not much else. The "smart" pointers and "move" are hard for me
to reason about still. I'd have an easier time reasoning about raw pointers
and references, mainly because that's all I had in my early C++ days and C
days (of course). I think things like asan and ubsan are far more helpful even
with plain C than features like smart pointers.

I've tried Rust. The author of TFA linked to another article explaining that
rust tricks you because it looks like languages you have used before, but it's
really not like them. That made me feel better about my experience. I found it
to be very frustrating. I'll have to try it again with a different mindset.

I haven't tried go, but I don't feel like it's a viable embedded programming
language because of it's garbage collector. At least not for tightly
contrained embedded systems. I'm honestly not sure rust is going to work for
those types of systems either. Sometimes you just have to poke bits into
memory and I'm not sure how a super safe language will deal with that better
than C.

~~~
pcwalton
> I think things like asan and ubsan are far more helpful even with plain C
> than features like smart pointers.

I agree. Smart pointers are not effective safety features. They mostly add new
ways to get use-after-free. (shared_ptr helps a bit by automatically bumping
reference counts, but shared_ptr is often discouraged in modern C++, and there
are lots of ways to get around this, such as "shared_ptr&".)

> I'm honestly not sure rust is going to work for those types of systems
> either. Sometimes you just have to poke bits into memory and I'm not sure
> how a super safe language will deal with that better than C.

Read the "Writing an OS in Rust" series. Even in the kernel, you can have a
relatively small trusted computing base and then most of the rest of the code
can be safe.

------
watergatorman
C++ is a huge and complex language compared to C. [Compared size of the
standard reference document for each.]

C++ is complex to parse. Clang and Gcc use back-tracking to parse C++ and
there can be long compilation times.

Tiobe language rankings for May 2019:

Rust is ranked 34th at 0.335% below Lisp and Prolog

Go is ranked 19th at 1.114%.

In complexity and size, Go language is closer to C programming language than
either Rust or C++. [Rust and C++ are much larger languages than Go.]

Lastly, Rust does not appear to have a standard BNF grammar specification and
I counted around 33 FIXME unspecified sections in the reference document for
Rust. I haven't even discussed the number of unstable features in Rust. in the
Ref

------
ochronus
It's a pity the author misses on the nice language features of Rust. Compared
to Go or C++ that can be more appealing to some engineers. I mean for example
traits, pattern matching, immutability and the functional features.

~~~
ncmncm
Rust does (still) have the advantages of a clean slate. Default const, default
pass by move, move that can't fail are nice things C++ can never have because
they can only be in there from the start.

The future will identify other features, in other languages, that Rust can
never have, for the same reasons. Rust is very quickly accumulating
unfortunate accidents that will make is seem less shiny as it matures. That is
just a natural progression.

Will Rust ever be mainstream? It is still possible. In five years it either
will be, or will be fading and something else capturing attention it
commanded. Only time can tell.

~~~
majewsky
> Rust is very quickly accumulating unfortunate accidents that will make is
> seem less shiny as it matures.

Are you saying that Rust is rusting? :)

------
ufmace
I think I'd agree that it's good to be at least familiar with all 3. I
honestly haven't really touched C++ in a long time, and don't know anything
about its newer and more advanced features. Might be worth doing? I honestly
have no idea how you would do something like pull in a utility library in C++
without wrestling with makefiles and compiler flags.

I have worked with some Go, and found it reasonably practical, if a little
boring and verbose. Not necessarily a bad thing if you're writing a big
program with a large team with widely-varying capabilities. But it's hard to
get the enthusiasm to write more Go recreationally. The standard library is
remarkably thorough, though I'm a little disappointed at how bare-bones
dependency management and control is.

I find I enjoy Rust rather well. I don't consider myself to be particularly
smart, but I haven't run into much trouble fighting the Rust borrow checker.
It does force you to think more about exactly what should own what at any
particular time, and exactly what to do in any particular error situation,
which is probably a good thing. Sometimes you have to throw some clones and
random &s around to get things working, but I've always been able to sort it
out so far. And it's the first language in this space with a dependency
management system that actually compares to dynamic languages like Ruby.

~~~
majewsky
I find myself nodding along with everything you've said, except for this:

> I'm a little disappointed at how bare-bones dependency management and
> control is.

Is that referring to Go modules, or to the situation before it? I just started
using Go modules in my active projects, and I find that it matches your
overall characterization of Go: reasonably practical, a little boring.

~~~
ufmace
That refers to the situation before it, I suppose, since I'm not sure what Go
modules are. I haven't messed with Go much in a few months though. If it lets
you specify somewhere which packages/modules your Go project uses and what
versions are okay, and upgrade packages within the permitted version range
without disrupting other Go projects you're working on, then it might be just
what the language needed.

~~~
majewsky
Yes, it's pretty much that.

------
mailslot
Why not all of the above? Then you can choose the best language for the task
at hand. They each have their own unique strengths.

~~~
geezerjay
It takes time to master a tool, doubly so if the tool is still being actively
developed, and the investment in time and energy to develop a skill needs to
be allocated at the expense of some other activity.

~~~
mailslot
Mastery is different. You can still be highly proficient in short time without
knowing every nuance. Then, you can choose which one feels best and is worth
your time pursuing more.

------
watergatorman
A limited comparison of C, C++, Go, Rust:

Go and C seem to have a large number of available software tools.

Based on the "size" of the reference documentation alone, C and Go appear to
be the simplest to learn for beginners.

A beginner coming from a C background might choose to learn the "Go" language,
of the 3 available choices: C++, Rust, and Go.

Other than it's declaration syntax, Go appears to have been designed to be the
most familiar to a C programmer.

C++ is very large and complex, just look at the size of the reference
documentation. The 4th edition of "The C++ Programming Language" doesn't even
have an "Appendix A: Grammar" anymore.

Rust doesn't appear yet to be stable enough to even specify a BNF for it's
grammar.

Of course, there are other programming languages out there that maybe are even
better for a C programmer to learn, but we were not asked for our opinion of
other PLs.

------
_xerxes_
I very much doubt Rust is going to get much traction in embedded. C++ is
barely being used and even when it is, it is usually "C with classes" being
written by C programmers forced to switch.

------
ncmncm
Easy answer: Yes!

To first order, it doesn't matter which you pick, because we will all be
better off than if you continue producing C code.

For production code, it is probably too early to switch to Rust, most places.
Give it five years. But it won't be a mistake, then, to have five years'
experience with it.

Rust and C++ will require more learning and adaptation than Go. Don't be
fooled by C++'s apparent similarity to C: to get the benefits, you need to
code the modern C++ way to reduce the window for low-level mistakes. Rust
makes it hard to code the C way, so needs less coding discipline, but the Rust
way takes more getting used to.

Both Rust and C++ can be substantially faster than C, for different reasons.
C++ is better at capturing semantics in libraries. Rust knows more about what
code is allowed to do, and can optimize accordingly.

Go is probably easier to switch to from C. There is not as much to learn. It's
garbage-collected, so there are places it won't go, but most people won't need
to go to those places.

It is never a mistake to know more than one language. In a sense, you don't
have to choose one, you only have to choose what to learn first.

~~~
flukus
> Both Rust and C++ can be substantially faster than C, for different reasons.
> C++ is better at capturing semantics in libraries. Rust knows more about
> what code is allowed to do, and can optimize accordingly.

People have been saying this for decades about various languages and C is
still the standard for performance except for a few specific cases. How many
more decades until we can consider this "sufficiently smart compiler" a myth?

~~~
quicknir
Uhm, citation needed? Most of the most performance critical industries like
game dev, high frequency trading, are primarily in C++, not C. Well written
C++ tends to be more performant than C largely because there's just much less
indirection in using templates than C equivalents (function pointers, void*,
etc). And compilers are already smart enough to optimize out most C++ compile
time abstractions.

~~~
flukus
> Uhm, citation needed?

Pretty much every benchmark I've ever seen, I provided one further down but
here's another one: [https://thenewstack.io/which-programming-languages-use-
the-l...](https://thenewstack.io/which-programming-languages-use-the-least-
electricity/) . Yes benchmarks can have many pitfalls but when literally all
of them show the same unsurprising result (that more abstraction means worse
performance) I think it's safe to trust them. Have you got a citation that
shows c++ generally outperforming c?

> Most of the most performance critical industries like game dev, high
> frequency trading, are primarily in C++, not C

And I'd be willing to bet that the more critical components look a lot more
like c than c++, not "modern c++".

> Well written C++ tends to be more performant than C largely because there's
> just much less indirection in using templates than C equivalents (function
> pointers, void*, etc)

Yes that's one advantage, it's one of the few specific cases where c++
performs better that I outlined. Even then _Generic_ in C can often give you a
way to do the same (in an uglier way).

------
kalium-xyz
None of the above, renewal for the sake of renewal is not a good thing which
we have too much of already in IT.

