Ask HN: Learn C++11 or Rust in 2022?

71 points by sharedptr ↗ HN
Python/Golang/C (ye, C) day-to-day job here.

I am interested in either updating myself on (C++11>) or going the Rust way. I see a lot of criticism/hate of C++ lately (mostly due to the comittee), but the tooling and libraries are there for multiple areas.

Rust is also interesting to me from a security standpoint.

So I don't really have time to invest in both languages; any directions?

160 comments

[ 3.7 ms ] story [ 257 ms ] thread
Between C++ and Rust, my bet would be that you decide Rust.

But—also learn Zig in addition to Rust.

Having seen first-hand how so many threat vectors these days are now supply chain attacks, having reported CVEs and earned P1 bounties in memory safe languages, and having worked on static analysis systems to detect zero day exploits—I'm also impressed by Zig's overall approach towards safety, as being more than only memory safety.

For example, this comes through in Zig's extreme simplicity and explicitness, and also how Zig enables checked arithmetic by default for safe builds. For people who haven't worked in security, integer overflow and wraparound may seem like small things, but they increase the probability of exploits such as buffer bleeds, i.e. attacks like OpenSSL's Heartbleed, which are often remotely accessible and easier to pull off than a UAF.

In fact, no language is 100% memory safe, i.e. able to prevent a memory buffer bleed, because these are logic errors with respect to the protocol. However, explicit control flow and checked arithmetic do help to close semantic gaps and minimize ambiguity, which is what good security comes down to.

Of course, Zig only offers spatial memory safety, and not temporal memory safety like Rust. So Zig is more memory safe than C, and less memory safe than Rust or JavaScript. Nevertheless, Zig is safer than Rust when it comes to being able to handle memory allocation failure.

Again, Rust's borrow checker is also valuable for concurrency safety, i.e. for multithreaded systems, but if you're using io_uring for fast I/O, then multithreading is less of the necessary evil that it used to be a few years ago.

Zig is something you can pick up in a week, with state of the art tooling, and fantastic C-ABI interop for libraries.

So... learn both!

I'm confused when people preach Zig and then safety in the same sentence. Zig has basically all the same problems that C++ has with a few extra bells and whistles. There are perfectly good reasons to like Zig, but it being "safe" is not one of them.

> For example, this comes through in little things like Zig's extreme simplicity and explicitness

"Simplicity" does not mean safety. In fact simplicity means you can't describe hard problems easily without being overly verbose, which means more code and more attack surfaces. Problems are what can be simple or complex. If your language advertises "simplicity" it just means it can't solve complex problems in straight forward ways. Zig is just repeating the mistakes of C++ as well as all the mistakes of Go.

> or people who haven't worked in security, integer overflow and wraparound may seem like a small thing, but they increase the probability of buffer bleeds, i.e. attacks like OpenSSL's Heartbleed, which are often remotely accessible and easier to pull off than a UAF.

Zig does exactly what Rust does in this case.

> In fact, no language is 100% memory safe, i.e. able to prevent a memory buffer bleed, because these are logic errors with respect to the file or protocol format.

What are you trying to argue here? Buffer bleeds can't happen in safe rust.

> The borrow checker is obviously great for multithreaded systems, but if you're using io_uring for fast I/O, then multithreading is less of the necessary evil that it used to be a few years ago.

Syncronization is a problem in any kind of multitasking. Whether that happens inside or outside the language is the only question. The OS can have all the same problems your code can have. https://mobile.twitter.com/axboe/status/1505335772706091011 Also io_uring assumes you're only ever writing for Linux.

> Nevertheless, Zig is safer than Rust when it comes to checked arithmetic or being able to handle memory allocation failure.

This is simply incorrect. Most of the problem with unchecked overflow is for buffer overflows, which are fully caught. Rust gives options to handle memory allocation failure if you want to handle it. Generally though for most applications simply crashing is completely fine.

Zig is a competitor to C, I think that really clarifies its design decisions. Eg., It's use of a interpreter during compilation to process macros, redresses C's purely textual approach.
> I'm confused

Thanks, I've tried to clarify that Zig provides spatial memory safety but not temporal memory safety, so hopefully it's less confusing.

> "Simplicity" does not mean safety.

Ceteris parabus, complexity breeds bugs and simplicity improves the probability of safety. For example, if I were auditing a piece of code for security, I would prefer the simplest correct program to the most complex correct program. Reduced surface area means reduced area for attack.

When I say that Zig pursues simplicity, I also mean this as high praise, that Zig is highly "orthogonal". In other words, able to solve difficult problems with a minimum of overlapping features. For example, Zig's comptime gives you generics, but also gives you so much more, plus there is also type safety throughout Zig's comptime, yet it eliminates the need for macros, and is more versatile, powerful and flexible at the same time. It's incredibly elegant. Nothing left to add, nothing left to take away.

> Zig does exactly what Rust does in this case.

Things like checked arithmetic matter and should be enabled by default in safe builds, yet Rust does not actually do this in safe release builds. Zig does and I hope that Rust one day will.

> What are you trying to argue here? Buffer bleeds can't happen in safe rust.

By definition, buffer bleeds can in fact happen in safe Rust. The borrow checker can protect against UAF and overflow, but the borrow checker can't protect against all kinds of underflow, which is what a buffer bleed is. You can even pull them off in JavaScript.

No language is actually 100% memory safe, not with respect to buffer bleeds.

> Reduced surface area means reduced area for attack.

First of all, that's security, not safety. Lots of software exists in an environment where it isn't going to be attacked.

> Things like checked arithmetic matter and should be enabled by default in safe builds.

Rust offers actual checked arithmetic - for example, suppose I have a 32-bit signed integer (i32) and I want to add something to it, in Rust I can choose the most appropriate of:

add - also presented as the + operator, in debug this will panic on overflow, but in production I can choose, either panic or just have it wrap silently

checked_add - at runtime check for overflow and get either None or Some(i32)

overflowing_add - this time instead of Option we get a pair back, with our (wrapped if necessary) numeric answer and a boolean saying if we overflowed

saturating_add - addition saturates at the minimum and maximum thresholds

unchecked_add - even in debug builds this is not checked (yes it's unsafe)

wrapping_add - this performs the most likely native hardware behaviour, wrapping numbers around at the limits

You might also realise your variable should inherently have certain arithmetic, for example a 16-bit PCM sample should always have saturating arithmetic (getting this wrong is one reason badly written older audio software can sound bad) so you can make them Saturating<i16> or maybe you actually want wrapping arithmetic on the simulated 32-bit CPU registers in your Motorola 68000 simulator, so you use Wrapping<u32> for them.

The debug behaviour for the trivial + operator is not intended to be your best defence, if you're sure you want wrapping, write that down, if you're sure you want to check, write the check. But sure, if you somehow want your release code to panic, but don't want to write the panics out by hand, you can tell the compiler you want this in release builds.

> By definition, buffer bleeds can happen in safe Rust.

Nope.

> The borrow checker can protect against UAF and overflow, but it can't protect against all kinds of underflow

And it doesn't, in safe Rust the actual bounds checks are emitted, and they only get elided in most cases because in idiomatic Rust it's clear to the compiler that the checks are unnecessary (e.g. iterating over items in a vector, the compiler knows how long the vector is, and it can see we're starting at the beginning and stopping at the end, so, we don't need the bounds check and it won't actually be emitted in the machine code). thing[index] is bounds checked in safe Rust.

> No language is actually 100% memory safe, not with respect to buffer bleeds.

Many languages are 100% memory safe. Most fascinating here is WUFFS which - in exchange for its restricted purpose - gets to be both entirely safe and faster than the C (or C++, or Rust) you'd actually write.

You literally can't write a "buffer bleed" type goof in WUFFS. I don't mean "You won't because it's so easy to get it right" or even "It will warn you about the problem at runtime so you can fix it". I mean code which can exhibit that bug does not compile.

> First of all, that's security, not safety. Lots of software exists in an environment where it isn't going to be attacked.

I use the terms interchangeably on purpose, because safety and security are really two sides of the same coin. In the past, I've worked in security and I now work in a domain where safety is critical. It's my experience that the two fields have considerable overlap.

We can always get better at interdisciplinary sharing of knowledge.

> Things like checked arithmetic matter and should be enabled by default in safe builds, yet Rust does not actually do this in safe release builds. Zig does and I hope that Rust one day will.

The entire origin of unchecked arithmetic being a problem originates from their use as indexes to buffers. If you solve the indexing buffer issue you don't need to completely expand every single mathematical operation to a checked one which slows down the code. If people want checked artihmetic for some reason in the rare case that it matters in a non-buffer case, then they can used things like checked_add.

> In fact simplicity means you can't describe hard problems easily without being overly verbose, which means more code and more attack surfaces.

Hence simplicity is not a desirable goal. We need to create complex languages so that fewer people can understand and use it in a few projects and write very less code. Less code means less bugs. ‘Complex’ is the way to go. /s

> I'm confused when people preach Zig and then safety in the same sentence.

Zig enforces correctness much more than C or C++ does (e.g. no implicit 'lossy' conversions, much stricter and enforced error handling, no implicit null, etc.), so it's completely fine to say that Zig is much safer than C or C++.

The main difference between Zig and Rust is the borrow checker, but a lot of memory corruption issues in C and C++ are "second order effects" of sloppy code which would be caught in Zig either at compile or runtime.

Except the little detail about sloppy use after free.
Agreed but doing this at compile time would require some sort of pointer lifetime tracking in the compiler. Don't know how much of this is feasable without going "full borrow checker", but static analyzers for C do a similar thing, by far not as watertight as Rust of course.

The General Purpose Allocator can optionally catch use-after-free by not recycling virtual memory addresses, not very efficient for small high-frequency allocations of course, but then Zig isn't an OOP language either (where it would be common to create and destroy massive amounts of tiny objects).

> ...but static analyzers for C do a similar thing..

Exactly, which begs the question why bother with Zig at all.

Zig is a much more ergonomic language, toolchain and build system. And since Zig is also a C/C++/ObjC toolchain, it's not about "Zig or C/C++", but about "Zig and C/C++" (at least from my PoV).
From my point of view it isn't enough to warrant adoption over existing alternatives.

Maybe someone proves me wrong with some killer application that makes Zig unavoidable for the rest of us.

Counterpoint: Zig is unstable (as in, <1.0 release) and the docs are still pretty lacking. You’ll find yourself reading source code if you want to do anything nontrivial pretty much.

Stick to C++ or Rust, which I won’t weigh in on here. But both are much more mature.

Also there's no job market for it.
I don't think Zig is recommended for production use. It's not at 1.0.0 yet.

That said, there are at least three stealth-mode SaaS companies I know of betting on Zig for their performance sensitive / low-latency software. Where I work, we're tracking Zig's nightly build and follow/contribute to Zig progress and stability roadmap.

Zig hits a sweet spot between C and C++. It feels really nice to work in -- in a way that many people describe Go. I think Zig is a very attractive option for allocation sensitive programs like games, audio, or purpose-built data stores. Give it a look and decide for yourself.

D had a couple of such SaaS and doesn't seem to have helped much in the end.
see? learn Rust, but yeah, also learn Zig, or whatever new flavor of the day. No thanks. I don't want my tool set to change every year. I got out of web dev exactly for that reason. I'll stick to my C++ or C, thanks.
And your software will continue to have memory safety issues.
memory safety issues are the result of poor software engineering.
History has demonstrated over and over and over again that c/c++ code above a certain complexity threshold (which is fairly low), _will_ have memory safety issues. It doesn't matter how good you are at engineering.
but all the companies are making people do coding inteviews now. didn't that solve the problem????? apparently not.
If the interview question was find the memory vuln in this giant code base, I would probably fail.
FYI, the fact that you can do poor software engineering in safe Rust (or any memory-safe language) and still do not have memory safety issues completely disproves your statement.
Just learn both. Find the time.

From a practical perspective, if you're short on time and want a return on your investment, C++ will open up more opportunities on the job front.

my personal opinion is to learn Rust and something like zig or nim
Man I have not heard of those last two wow. Well 2016/2008 not really brand new either.
Unless you're going to be doing something that specifically requires C++ (some game engine related code comes to mind), go with Rust. Most real-world code (by number of codes and lines of code) is something else than C/C++ nowadays, just because of developer velocity and a larger hiring pool.

Yes, you can get that last cycle of power from a piece of hardware by going with C or C++, but on the other hand finding people who can do that is time-consuming and expensive. And in many cases eventually not worth it.

"C++" is such a big concept toi grasp fully, that I don't see the point of studying it unless you're getting paid for it.

How do you begin to get paid for it without studying it first?
Get an employer who lets you learn on the job.

Programming languages are like actual languages, after you know the first two or three, the fourth one isn't that much of a hassle (there are exceptions of course).

I didn't know crap about C# when I started my current job, but I did have a decade of Java under my belt. Took me about a day to figure out the basics. Ifs and switches and functions and classes are the same everywhere.

If I would've had to study something like Haskell or Scheme, it would've taken a bit longer.

Some employers are actually far-sighted enough to spend money training their employees.

So e.g. you hire a bunch of fresh graduates who've learned some programming maybe Java and Python, and maybe have other expertise you value (e.g. maybe they're aerospace engineers and you write control software for jet engines) and you spend money hiring somebody capable to stand at the front and teach them how to write C++. It's their job to learn this, so you can do it pretty intensively, e.g. lecture slot / exercises / break / repeat.

C++ is a big sprawling language, but you can make a good start on them in two weeks.

You've presumably worked somewhere with at least some onboarding or spin-up time. Somewhere you weren't employee #1 and responsible for buying your own stationery and cleaning the toilet ? What did you do on day one? Fire training? How to use the CI system? Anti-bribery? Getting your photo taken for an ID badge? Maybe some "easy" first tasks just to learn your way around the systems?

If you have a job where you turn up on day one and are just as productive as a long haul employee, I have terrible news for you - you are the most replaceable person in your organisation and you are going to get fired.

> Most real-world code (by number of codes and lines of code) is something else than C/C++ nowadays, just because of developer velocity and a larger hiring pool.

This is simply not true. Examples of major software that is being actively developed:

- Lots of compilers/runtimes (gcc, LLVM (which Rust builds upon), Java/JDK/JVM, Swift, node.js) - All major browsers and browser engines (Chrome/Chromium, Firefox, WebKit) and thus Electorn - Lots of rich client applications using either some Windows API, or something like Qt, or Electron (JS + C++) - Major game engines such as Unreal, Frostbite, CryEngine - Major OS'es graphics API build upon C++: Microsoft's Direct3D, Apple's Metal

And this is completely ignoring the embedded world, where C++ competes at least at some higher level with C.

All of this requires C++ engineers.

Again, this is a tiny portion of actual coders.

The amount of people actually _making_ compilers and runtimes is multiple orders of magnitude smaller than the people using them.

Same with browser engines and game engines. For every coder doing the actual engine, there are a hundred others just using the engine, not touching C++.

You did list a pretty substantial portion of the segments where C++ is a valid choice and in many cases (along with C) the only option.

When the car's automatic gearbox breaks down, it is nice that there are some mechanics around.
True, but not everyone with a license needs to know how to rebuild a gearbox =)
Depends, on some countries getting a license means acquiring basic repair and first-help skills. :)

In any case, the point was that those that know how to repair the gearbox must come from somewhere.

It's not like they are equivalent. I'd rather stop programming (or any kind of computer science related career) rather than take a job doing business Java or writing game logic in Lua or C#.
> "C++" is such a big concept toi grasp fully, that I don't see the point of studying it unless you're getting paid for it.

Not really necessary to grasp the entirety of the language to use it effectively, I dabble in C++ here and there and usually treat it as a fancy C just using stuff like smart pointers, strings and vectors. Even learned some C++17 stuff which made what I was trying to do a lot simpler though I can’t remember what I was up to, think it was some boost lib I was already using that got promoted or std::variant shenanigans with my asdl generator — definitely yaks were being shorn I can say for sure.

There is just not enough information in your post in what you want to do with your knowledge.

If you have a long time horizon, Rust is the safer bet, if you want a job fast, C++ has probably more job offers.

Honestly my main short-time goal is to write performant applications, I have some processes in mind that would work way better if I could manage memory instead.

At the moment I just write bits in C whenever I need it but when it scales in a decent size I would just write the whole thing in C++/Rust

With C++ realistically memory management is so hard that if you want to go solo, and you don't want to debug segfaults all the time, Rust is definitely the way to go. It teaches you manual memory management like nothing else.
> With C++ realistically memory management is so hard

Honest question as I'm not a C++ developer: Even with all the new C++17/20 stuff?

The problem is that it's too late to add linear typing to C++ at this point and get rid of all other types. So I would say yes.
Problems with memory management are a fading memory when coding modern C++.

All the things Rust advocates insist cannot be done safely in C++ are now trivial. Use-after-free, leaks, buffer overruns, what-have-you, no longer need any attention to avoid if you stick to modern C++. Some people insist on coding as if it were C, and bring along all of C's failings. Leave them behind.

Unfortunely, only when working solo, or with a team that really embraces security.

Those people that insist on coding as if it were C are still a very big group across the industry.

I took an Earley parser library written in Java and ported it to C++ with just using smart pointers everywhere for memory management and it Just Works™. Like magic really as I can’t recall having to hunt down any segfaults and I spent a bunch of time debugging that thing because porting from Java wasn’t really a copy paste operation especially since I never mess with Java so don’t know the standard library stuff.
Unless you're manually implementing data structures or something similar you basically never need to manage your memory manually in modern C++. std::vector takes care of most your needs and smart pointers exist for the few cases where it doesn't. There's not really a lot of difference to Rust there except that OOB access is a panic in Rust and (most likely) a segfault in C++ but you can trivially enable that checking by putting the STL in debug mode.

C++'s problem is that most people never learn it properly and think "C/C++" is a thing because most courses/tutorials are stuck in the 90s and effectively teach shitty C with classes and iostream. Rust is great and has really nice features which I'd like to have in C++ too (like pattern matching) but memory safety is really not an issue in proper modern C++. I'm aware that this is a bit of a "you're just holding it wrong" but pretty much all languages have things you shouldn't do anymore once they evolve, it's just more obvious in the one with strong backwards compatibility requirements to the ancient language created before all the modern research into language design.

It's entirely possible to invoke memory unsafety in modern C++.

    std::vector<int> v {1, 2, 3};
    int& x = something(v);
    something_else(std::move(v));
    x = 42;
Is this UB? Impossible to tell without examining the code of the functions involved!
Nobody said it's impossible, it's just generally not an issue if you write normal code (read: stop treating C++ as C, they are completely different languages). There's only very little difference in how much you need to think about lifetimes and stuff between Rust and modern C++, it's far from being "hard". Sure Rust holds your hands a bit more in those regards but you can also just turn on address sanitizer and friends and then you have a very similar experience.
> If you have a long time horizon, Rust is the safer bet

I mean, maybe. Or maybe it gets replaced by something else.

I assume you know an older form of C++; the language changed a lot over the years, and the more recent features are "better" but they also make C++ (even) more complex. It suffers from ugliness, non-orthogonality, over-complexity, among other diseases, but it is still somewhat practically relevant. Rust is worth learning for its 1. avoidance of null and memory leaks 2. great error handling 3. excellent compiler error messages 4. concise notation (perhaps except macros, Common LISP wins here IMHO).

So first learn Rust, later learn C++11+ (by the time there will be a successor of C++11 that may look even less like the C++ you know).

Learning Rust will develop your thinking and taste, and this will then help you judge the flavour of C++ that you will be learning later (and because you'd update your C++ skills later, you may skip another C++ legacy flavour in the process).

C++ has a myriad of wonderful language features that exist entirely within C++ and cross no language boundaries. I really adore C++ as a language but unfortunately I find little pragmatic use for it unless I'm working 100% inside C++ and using native APIs only. If you're doing that, it's a dream. Rust, on the other hand, speaks the same ABI as C, and with serde, can read and write to most formats and/or APIs with utmost ease.

C++ I find can get a little unwieldy quite fast, but is generally easier to keep simple. It maps to higher-level concepts in easy and intuitive ways. Rust, I hate to say it, but unless you know best practices / idiomatic Rust from the start, you'll have to do a lot of refactoring as you learn the language. Some constructs simply aren't possible using safe Rust. Many embrace the limitations, many else frustrate themselves again and again until 'the Rust way' drills into their heads. But, of course, once you get a feel for it, it's pleasant to write in.

How much difficulty you'll have with Rust or C++ depends on what problems you try to solve, and what your approach to programming is generally. If you're more of a pragmatic "I write simple programs that actually do things" I don't think you'll have any problems with Rust. It's very straightforward. And the tooling is second-to-none. If you like to partake in exploratory programming, trying out different theoretical models and different abstractions, C++ caters to that by allowing you to write more elegant designs than in Rust, with the downside that it also lets you make worse mistakes.

The wider cross-language library ecosystem is mostly C-based I've found, so, in C++ you can just use those libraries directly with no hassle (the only hassle being the build system, or lack thereof). Rust can use those libraries as well (as long as you don't have a gut-reaction "ew" to using `unsafe` everywhere) but unfortunately the safe and idiomatic Rust library ecosystem is kind of on the bleeding edge at the moment. Hopefully things will stable out soon, and all these hip new technologies will come to fruition, but that day is not today.

I know this isn't really nudging in one way or another but really it comes down to what you value in a language and what projects you want to see through using these technologies that will determine which one you like better. Have fun!

> C++ has a myriad of wonderful language features that exist entirely within C++ and cross no language boundaries. I really adore C++ as a language but unfortunately I find little pragmatic use for it unless I'm working 100% inside C++ and using native APIs only. If you're doing that, it's a dream. Rust, on the other hand, speaks the same ABI as C, and with serde, can read and write to most formats and/or APIs with utmost ease.

This seems like a weird statement. Yes, C++ has a load of features you can't express in a C API. But so does Rust! Yes, Rust can produce and consume libraries with a C API. But so can C++! They're in pretty much identical positions here, aren't they?

It's true that serde is great, and C++ doesn't have an equivalent (AFAIK). But C++ does typically have excellent piecemeal support for popular serialisation formats.

I find it difficult to articulate, so forgive me if I'm not getting my point across, but the gist of what I'm trying to say in that section is less about straight binary compatibility and more about API design in general, playing to the respective language's strengths. I feel like Rust encourages more "C-like" APIs, and its added features (such as memory safety) are in effect the whole running time of the program, regardless of where that memory comes from or how it's initialized. On the other hand, C++ has something of a vendor lock-in regarding how it functions - RAII, constructors, exceptions, inheritance, etc. etc. all assume you have objects with a lifecycle that starts and ends in C++, and that those objects see most of their use according to C++'s object model. All of C++'s features come together in a brilliantly harmonized way and build off each other, but, if you forgo even some of those features, you end up missing out on most of them.
It's possible to have some parts of what serde does if you restrict yourself to aggregates (no private members, no explicit constructors), e.g. your types are simple structs such as

     struct foo { int x; std::string label; };
Here it's possible to serialize/deserialize this structure in a generic way without having to annotate it - currently it's a bit complicated to implement so libraries help doing it (e.g.https://github.com/apolukhin/pfr_non_boost) but in 23 the missing language feature that makes the code trivial to write without any library should be there.
I don't understand why someone who has so much open source information, has the intelligence to learn C-level languages, and has a certain experience in the industry, would ask such a question.
Maybe they just want to try to see which way the wind is blowing before making a decision which would require more than a little effort to achieve?

I’m actually surprised that the general consensus isn’t rust as that’s the new shiny plus the people saying C++ are giving very valid reasons beyond the usual language dogma arguments that these discussions usually devolve into.

I mostly use C when I need to speed up some bits in our codebase; and I have no chance to ask people really working in C++/Rust which can give help me decide; the people I know use C++ for games or QT. The ones I know that touched Rust gave up after 1.5 weeks.

As you say I wanted to know how's the scene at the moment; I am very disconnected from how they have both evolved and their future (mostly because what I see is hate to C++)

Yeah, the unreasonable C++ hate is real. That said, from the modern perspective, the old versions of C++ do suck very much. If you're not even acquainted with C++11 yet, you should definitely check out C++20.

Rust is less expressive than C, but likewise it does give less chances to shoot yourself in the foot.

C++ is often derided for its complexity, arising from its long development. While it's true that C++ allows many wrong ways to do something, I don't think that should really be a problem. The language's main problem is societal: C++ (and C) is often used by people who haven't bothered to learn the language. E.g. one can't rely on random unknown C++ code handling integer overflow and type punning correctly, so in such cases it's wise to compile with

    -fno-strict-aliasing -fno-strict-overflow
A part of the problem is that C/C++ is so traditionally established, it's taught as as an introductory language at universities, for example. But it's usually taught wrong, because there's no incentive to teaching it right, and trying to teach it right could in fact be counterproductive, if the goal is merely to introduce someone to programming. This is why I think it would be best to teach Python or Julia as the introductory programming language, and (modern) C++ only afterwards.

Rust's advantage in this regard is that it's more centralized, it's lead by a foundation instead of being standardized, so everyone who learns Rust, learns the one, correct way to do things.

I learnt it at university back then, but I had already toyed with C++11 so I always made puns and called what they were teaching C--. Essentially they were teaching a very old version and the evaluation machines ignored all the "modern" bits back then.

My idea is to either C++20 (not sure if there is a resource to learn directly from C++20 or if there are compilers supporting it) or Rust, personally I would go for C++ seeing as there's a wider ecosystem and tools out there, lots of libraries (which are a bit of a pain to use sometimes) and it is almost anywhere.

But to be fair, I am out of the loop of C++/Rust and what I see in my internet circles is Rust > C++ mostly because of the memory safety; which makes me wonder if it is worth or not; also lots of C++ hate which reminds me of PHP.

I just have a hard time making decisions.

By the end of the day your employer will decide which language/version is to be used on a project, so you should check with your employer. That said, even C++98/03 is well an alive; as a consultant I still see a lot of industry projects using C++98/03, some with a few elements of C++11; I rarely see C++17 and never see Rust projects.
(comment deleted)
Erratum: s/less expressive than C/less expressive than C++/
C++20 is going to be much friendlier. If you're new to C-like languages though, perhaps start with C and work up to C++. The foundations are important to understand, and you'll appreciate why RAII is important.

EDIT: Ah yes, the "crawww C is unsafe, use rust crawww!" downvote crowd is out in full force today.

The downvotes are probably because you said "start with C" while the OP has clearly stated they have experience with C and use it in their day job.

P.S. I haven't downvoted you.

Oh I missed that line, thanks. The advice still stands, however - perhaps not to OP. But I think it's even more reason to learn C++20 in OP's case.
I use C at work and in the past for hobby projects C++ (11) to do some modifications to Quake 3.

Is C++20 support in compilers already? MSVC/GCC/Clang

Not fully, but the important pieces yes. Clang and GCC in particular, not sure about MSVC as I don't use it.
Starting with C is the worst way to learn C++. You start out with bad habits you then have to unlearn.

Unlearning bad C habits is hard because the language accommodates them for as long as you continue to cling to them. You need to consciously decide you will use the new, better way. Once you have done each once, there will be no temptation to backslide.

Fully disagree. Understanding pointer semantics is a pre-requisite for understanding RAII.
I know C++ since 1993, I am quite curious how pointer semantics have anything to do with RAII.
Yeah, doesn't make sense. Pointers are less useful in C++, because we have better things now.
Of course we do. You still need to know how pointers work to use RAII effectively, though.
Not at all, because RAII is about constructors/destructors, and not at all about pointers.

Heap allocated data is one special case of OS resources that can be managed by constructor/destructor pairs.

What did being pedantic prove here?
The thread started with you insisting a C-level conception of pointers is essential to coding C++, which turns out to be false.

Learning C first is a very bad way to learn C++. One can pick up pointers later, and asm blocks after that.

Because smart pointers are still pointers under the hood. You're forgetting the time before you know what pointers were - people coming from higher level languages don't immediately grok the concept. By teaching them automatic memory management patterns like we use in C++ without teaching them why you need such things, they'll never fully understand the code they're writing.

It's like the "I know React but not JavaScript" crowd all over again.

If you think RAII is about smart pointers, you really don't understand it.

RAII is about resource management, regardless of where those resources live on.

Heap allocated, OS handles, indexes on a fixed sized buffer, network sockets, ...

Yes, I'm aware, thanks. Lifetimes, ownership, etc. are all overlaps of RAII and associated concepts.

Again, what did being pedantic prove here? You clearly understood what I meant.

Learn Rust. When you get to C++ later on, it will make you write much better C++ code. The other way, not so much.
Depends on which area you want to work on, anything related with GPGPU, HPC/HFT, GUI tooling, LLVM/GCC infrastructure will be focused on C++ for at least one decade, or more still.

For Cloud Native stuff, Rust might be a better option, specially due to the security focus.

It's a bit of a dilemma if we are talking about landing a job here.

With C++ you'll have more offers, but you are more likely to be unsatisfied with your job: in large corps you'll usually have to untangle lots of messy legacy codes; while in start-ups things are more likely to be done quick and dirty and the flexibility C++ provides doesn't make it any better.

With Rust unless you are in the US, it's gonna be extremely difficult for you to find an opportunity; even in the US I gather there are not many chances and I _guess_ recruiters would expect higher proficiency as Rust is known for its steep learning curve.

If you go for C++, don't start lower than C++20. MSVC has a chunk of C++23 done already
What is your objective? If it's to be exposed to new ideas, I suspect that you will find Rust more interesting. In general Rust's notions of ownership/borrowing will be new to anyone, but to a Python/Go/C programmer like yourself I suspect you will also enjoy learning about tagged unions (what Rust calls "enums"), pattern matching, and expression-oriented programming (e.g. how `if` can be used directly as a ternary operator).
C(+) on client and Java on Server, for eternity.
I would choose Rust. Today it might be that the market has more jobs on C++ and there are more codebases.

In the future, those codebases will only be the legacy ones and you will end up doing more maintenance with C++.

With Rust your investment of today will pay off in a few years.

Deciding what to learn today is an investment decision and you should look into what you think the future will look like. To me it looks Rusty. :-)

I think a valid concern might be - in 5 or 10 years, C++ still remains, just like Java and other "boring" languages. However, Rust might have been replaced by the next "Rust". That environment is still somewhat in flux.
I agree with you, it might turn out that C++ outlives Rust. I am seeing more codebases being created from scratch in Rust nowadays. We are just making bets on the opposite side. I guess we both agree that the deciding factor should be what you think the future will look like in 5+ years. Nobody knows what will happen in 5 years, then it is a bet or an investment decision you make.
I'm sure exactly the same comment can be found on Slashdot in 1997 with "Java" instead of "Rust"
Learn both. You're likely to encounter both of them at some point in your career. I also find it easer to go from modern C++ to Rust than the other way around.
Not for everybody, and I’m sure it’s not the most efficient way to approach it, but I personally felt that learning modern C++ was a good intermediate step before learning Rust.

Going to rust directly has been a very frustrating experience and made me give up.

Instead I spent time learning C++, I found out I could more easily transfer my knowledge/skills there. Once you become more proficient with the basics you learn about move, copy, smart punters, ownership, etc.

After some point you start to notice that you are basically doing in your mind exactly what a borrow checker enforce. So that made me curious and I tried rust again, and this time everything made complete sense and the language has been incredibly refreshing to work with.

This intermediate state was very useful for me to build my mental model and develop a better intuition, C++ made it simpler to do it in a more progressive way. And Rust is a fantastic langage if you can wrap your mind around it’s semantic and learn to work with the borrow checker.

> Going to rust directly has been a very frustrating experience and made me give up.

IMHO, you could learn Rust as a first PL by treating it as a functional programming language with a focus on purity, like a twist on ML or F#. The borrow checker rules and things like the String/&str distinction follow naturally from that POV. Then learn how "interior mutability" is used to enable more C-like procedural programming with shared mutable state.

I feel that by starting with FP, for example by starting with something close to ML in syntax and concepts, you cut yourself from too much of the programming world as everything else feels completely foreign and weird. But I get your point, you can approach it from the other side and also develop your intuition this way.
One reason C++ experience is so helpful with Rust is because the language was created by C++ programmers for C++ programmers, so most books and even documentation are written from that perspective.
This is something that's completely obvious to me. What I don't understand is why people online insist that Rust is so different and C++ knowledge is useless - I doubt I'd grok it immediately if I didn't understand C++.
I had the same experience. Went to rust from a memory managed language, had no idea why people liked it so much. Then, I had to learn some Delphi (and not 10, like 7 compatible), and coming back to Rust was a breath of fresh air, and I understood the value in the ownership system.
> I see a lot of criticism/hate of C++ lately (mostly due to the comittee), but the tooling and libraries are there for multiple areas.

I like C++ and my main caveat is that you don't just write C++. You also have to get good at tools like Valgrind and develop a deep intuition and understanding of what the language does under the hood. That's going to require a significant time investment and some people just don't have the right energy for it.

Nowadays the only reason I would learn C++ instead of Rust would be if I wanted to benefit from the much bigger C++ ecosystem, for example to build a game engine from scratch.

Surely in any language you would have to learn tooling ? What happens when your user report performance problems on Python, Java or JS programs, you surely use some profiling tool there, no ?
If you use Python and JS chances are you do some form of web development, where most performance issues have to do with I/O, and most of those I/O issues are caused by bad queries. It ultimately comes down to using application performance monitoring software and analyzing query plans. Memory issues are an oddity and are usually caused by users doing stuff like uploading gigantic files.
> using application performance monitoring software and analyzing query plans.

soo... tooling ? how is that different from using valgrind ? it's literally one click in my IDE to use it and it will show e.g. the time spent at each line of code directly in it.

> If you use Python and JS chances are you do some form of web development, where most performance issues have to do with I/O, and most of those I/O issues are caused by bad queries.

I don't know about this, what I know is that multiple times in my career I had people come at me with python software that was slow, and transliterating them almost line by line to C++ made them much, much, much faster.

Also I have all these apps on my system which apparently depend on python, none of them being a web app:

    Name            : 3dsconv
    Name            : anydesk-bin
    Name            : arandr
    Name            : asciidoc
    Name            : bind
    Name            : binwalk
    Name            : bpytop
    Name            : breezy
    Name            : carla
    Name            : ceph-libs
    Name            : cmake-format
    Name            : cppcheck
    Name            : cppman-git
    Name            : cython
    Name            : deluge
    Name            : deluge-gtk
    Name            : diffuse
    Name            : distcc
    Name            : fio
    Name            : fontforge
    Name            : fvwm
    Name            : fwupd
    Name            : gconf
    Name            : gcovr
    Name            : gdb
    Name            : gdb-common
    Name            : gdown
    Name            : glusterfs
    Name            : gnome-tweaks
    Name            : gobject-introspection
    Name            : gtk-doc
    Name            : i3-workspace-groups-git
    Name            : ibus
    Name            : inkscape
    Name            : iotop
    Name            : ipython
    Name            : itstool
    Name            : jack_mixer
    Name            : kajongg
    Name            : kig
    Name            : kitty
    Name            : kitty-shell-integration
    Name            : libffado
    Name            : libixion
    Name            : libopenshot
    Name            : libreoffice-fresh
    Name            : libsearpc
    Name            : libsigrokdecode
    Name            : lldb
    Name            : mallard-ducktype
    Name            : meld
    Name            : mercurial
    Name            : meson
    Name            : mono
    Name            : mypy
    Name            : namcap
    Name            : node-gyp
    Name            : nuitka
    Name            : openshot
    Name            : pahole
    Name            : paperwork
    Name            : pax-utils
    Name            : pcsclite
    Name            : perf
    Name            : ps_mem
    Name            : pyalpm
    Name            : pyside2
    Name            : qemu-tools
    Name            : reflector
    Name            : repo
    Name            : rubber
    Name            : samba
    Name            : scons
    Name            : seafile
    Name            : setconf
    Name            : smbclient
    Name            : smem
    Name            : solaar
    Name            : speech-dispatcher
    Name            : tellico
    Name            : thefuck
    Name            : thonny
    Name            : torbrowser-launcher
    Name            : udiskie
    Name            : virtualbox
    Name            : yelp-tools
    Name            : youtube-dl
    Name            : yt-dlp
    Name            : zim

incidentally, my day to day experience definitely does not classify any of the software I actually use in the "fast and enjoyable" category, except zim and tellico. Like, just launched a couple that I had forgotten about: solaar, a GUI for configuring logitech mice, and thonny, a minimalistic IDE for arduinos, etc. and they take actually observable time to start, on a 1k€ CPU, which I really find to be entirely ridiculous (and made me remember why I don't use them more).
Imo the biggest difference is that in the Python / JS world you can be considered a senior developer at many respectable companies and still be clueless about tooling, optimization etc. Most shops (exceptions being places that do a lot of ETL, data processing...) are OK with clunky Python as long as it is not unusable. On the other hand if you are working with C / C++ a more active approach is needed if you don't want your software to blow up.
It depends on which direction you want to go.

Rust is probably a better bet for web-related things. There is not much C++ there, and Rust seems to get some popularity. After all, Rust was originally made for Firefox.

For more industrial applications, or game dev, C++ is likely the way to go. Where I work, we do a lot of industrial applications and we have a lot of C++ projects, including new ones. Rust is not even on the radar. [Edit: C++ here is mostly C++11 now, with some C++98 and not much C++14 and later, I expect that we will get to C++17 soon enough but C++20 probably has a long way to go]

Forget about the criticism/hate of C++ and hype of Rust, it has little to do with practical applications.

It depends on the direction/industry you want to move in - depending on that you have to learn. The solution of the task will show you which language is more suitable.
I think you should tinker enough with both languages to learn their main concepts and then let 'outside requirements' guide you from there. E.g. if you're looking for a C++ or Rust job, or want to contribute to a C++ or Rust open source project, or just generally enjoy one language more than the other for weekend projects.

Also, if you're already fluent in another imperative programming language, it shouldn't take more than one or two weeks of a few hours after work to get an initial grip on both languages and decide whether you like them or not.

Personally, I find both languages equally frustrating for 'spare time stuff' (for different reasons though) and prefer simpler languages like C, Zig, Go, Python or Typescript (depending on the problem at hand).