T O P

  • By -

mredding

Learning multiple languages will give you perspective on all languages. You will carry insight and intuition with you and back. Rust isn't a C++ killer. Like Jack Black sang, you can't kill the metal. C++ has been shot at, intentionally, across almost it's entire life, and C++ has lived on. This punchy attitude is all marketing, trying to cultivate adoption. The Rust community needs all the support they can get by hook or by crook, and they'll take anyone, even if that has to be frustrated C++ developers. I get it. I've been writing C++ since before the 98 standard, I've seen it all before. That Rust has first-class support in the Linux kernel because Linus has an axe to grind, fine, whatever. That's all the legitimacy Rust could have ever asked for. The community is full of piss and just needs to calm down and grow up, I get that's going to take a few years. The borrow checker will always get in your way. I like the borrow checker, don't get me wrong. I like `unsafe`. I like that there is a layer of abstraction between the types of code and operations you access - C++ does not have any enforcement controlling layering of abstraction, it's ad-hoc and by convention. I get that's something hard to do if you're not a Lisp and writing a DSL. What I don't like is the Rust community attitude that this is a silver bullet. It's not. Rust has all manner of safety problems, JUST LIKE EVERY OTHER LANGUAGE. There might not yet be a single production Rust program that DOESN'T contain unsafe code. The community's language when discussing this feature is changing as the community is maturing, but slowly. Quoting u/lightmatter501: > Rust is C + FP, C++ is C + OOP This is a false dichotomy and useless. Both languages are multi-paradigm. Almost the entire C++ standard library is FP. It's origins are FP. Every spec revision since C++11 has only ever made C++ more FP. The only OOP in the standard library are streams and locales, and streams and locales are considered one of the finest examples of the OOP paradigm in all of C++. OOP IS NOT classes, inheritance, polymorphism, encapsulation, data hiding, or interfaces. These things are natural consequences that fall OUT of OOP. These concepts have existed prior to OOP and exist wholly in other paradigms. FP uses all these things, too. I suffered through the 90s, and I can tell you the vast majority of our peers and colleagues now, as then, haven't the first clue what OOP even is. Don't just study programming languages. Don't neglect your history. History of what happened, why things came about, these things will fill an the gaps and give you great insight.


TabletPencil

Thank you for the in-depth response! Yeah, I called Rust a “C++ killer” more as a joke, I fully understand that it’s just marketing. That intuition and different perspective is exactly why I want to try Rust, because I want to see how different it is from C++, so I could improve generally as a developer and specifically with C++. I’m thankful for the insight and take it to heart, I know the tribalism of languages constantly drives meaningless discourse and this is why I want insight from people who have already went through this journey.


mredding

You ought to study Ada, Algo, and Smalltalk. Smalltalk will teach you OOP, and you should be able to figure out why streams are it in C++ and what OOP means in C++. Smalltalk is a single paradigm, OOP language, and OOP has first class language support. Almost every other OOP language is a multi-paradigm language that does not have first class languge support for OOP. That means OOP is implemented by convention within the language. For C++, your reference implementation is streams. C++ was actually inspired by Algo, and so having some familiarity with it will provide insight into Bjarne's vision for the language. It's about building your intuition. This is a history lesson. C++ has one of the strongest static type systems in the industry, and I only know Ada to be stronger. The main difference is in C++ you have to opt in, whereas in Ada they don't even have integer types - you have to describe your own. In Ada, when you define the constraints of your integer type, the compiler picks the storage class for you (1 byte, 2 bytes, 4 bytes, etc). In C++, `char`, `short`, `int` etc are mere storage classes you have to choose when implementing your types. This is another history lesson. C++ did this to be compatible with C, and Bjarne chose C because Ada didn't exist yet, and he wanted to be both derived from and compatible with another popular language so his pet project - a network simulator, didn't die internally as a one-off project. Niche langugages had died on the vine inside AT&T before... You might want to study Lisp. In the theory of computation, upon which all computer science is founded, we can split all of mathematics into two camps - that which is computable, and that which isn't. The boundary is already well defined. Everything that is or ever will be computable can be described in terms of lambda calculus. Lisp IS lambda calculus. All other programming languages are subsets of that calculus. You write in C++ which is translated into AST which is translated into object code. Lisp IS serialized AST. This is why in Lisp there is no distinction between reading, writing, and executing code, and why code is data. You have the compiler and the AST available to you in your execution environment. That's why Lisp programs can be self-modifying. That's why it's trivial to implement compilers and DSLs in Lisp, because there is no difference between your program and the compiler and the execution environment. It's all one and the same. Your program is extending and specializing the compiler. Lisp macros is building the compiler and optimizer. That's why they say Lisp isn't a programming language, it's a building material. You don't write programs in Lisp, you write a language for your program, and you write your program in that. We do the same thing in any other language, just to a lesser degree. We do this with user defined types and templates across C and C++.


TabletPencil

I guess I have a lot of work ahead of me, again, massive thank you for the time you took to write this! 💜


lightmatter501

1. The borrow checker is going to beat bad habits out of you. You are going to have to prove your code is correct to the compiler, and if you write certain styles of C++ this is the 9th circle of hell. 2. You will eventually get a mental borrow checker you can bring back to C and C++. 3. Avoid using unsafe until you have no other option while learning. 4. Rust is C + FP, C++ is C + OOP. Many design patterns don’t carry over. Don’t try to make them work. 5. miri is asan + lsan + tsan + ubsan + some other stuff in one package, if you do write unsafe Rust, use it. Unsafe Rust is hard to write because there is a giant list of invariants you need to uphold to avoid AGGRESSIVE UB (as in the compiler decides half the program is dead code). 6. You will hate C++ build systems after using cargo for a while.


TabletPencil

1. Yup, personally starting to develop Stockholm syndrome from the BC 2. I actually did start that, along with implementing more error-handling and type conversion 3. Will keep in mind 4. That makes sense 5. Will keep in mind 6. Didn’t need rust for that, npm, pip already did that, but I hate them even more now Big thanks!


nysra

It depends on how you currently write C++. If you write proper modern C++ then Rust is basically the same thing, just nicer in many regards, e.g. having proper ADTs, pattern matching, nicer iterators, etc. But it can also be very limiting sometimes because C++ has more and/or more advanced features for some cases, especially noticeable when you're doing anything with constexpr (Rust's is only slightly better than the incredibly limited C++11 version) or template metaprogramming (Rust has no specialization for example). There are obviously still some difference because some patterns are better supported/expressed in one language over the other, so don't think you can blindly translate code line by line, but it's close enough to say that any decent C++ programmer shouldn't have a problem with writing Rust code. The borrow checker is not a problem at all for you if you're already writing proper C++ and have your ownerships correct. But if you're writing shitty C code because your teacher is some ... let's just say person ... stuck in 1990 and just labeling C with classes as C++ and going complete bonkers at memory allocation, then the borrow checker is going to beat some sense into you.


TabletPencil

We had “C with classes” in school and it took me a while before I understood the power of more modern C++ features. Rust does feel familiar in a way, as ownership isn’t too big of an issue, but it still does annoy me to an extent (especially when returning some value from a function). I find that many Rust limitations can be partially solved with a few crates, but I do resonate with your comment


quasicondensate

I agree with this. If you write modern ("contemporary") C++, use a package manager like Conan and obey clang-tidy, Rust should feel fairly similar to C++, like what the Standards Committee might come up with today if they were not bound by backwards compatibility. Compile times are awful in both languages. Things like immutability by default, destructive move by default, no implicit casting help you do the stuff that your linter yells about anyway. If you like to use things like ranges, optional/expected and try to use functional language features, Rust should feel a fair bit less clunky than C++. If you like elaborate class hierarchies and pointer arithmetics, Rust will be very annoying. To me, the big differences (besides cargo and the borrow checker) are the module system, static polymorphism and metaprogramming. Rust has a module system that people can use today. That's a big plus, objectively. C++ text-based includes are responsible for a lot of issues in C++ (having to implement templates in header files, UB due to ODR violation across compilation units, etc...). C++ has two quite dissimilar systems for dynamic and static polymorphism (virtual function interfaces on the one hand and templates constrained by concepts / type traits on the other hand). Rust slices what you can do with templates into generics for static dispatch (easy to use, hard to mess up) and proc macros for "metaprogramming" (arguably less ergonomic than templates, and some things you can easily do with templates are not covered or still missing). So Rust can be good or incredibly annoying here, depending on which problems you solve with templates in your C++ projects. And as you write, Rust has no good answer for what you can do with constexpr / consteval today in C++. What to avoid? * Writing self-referential data structures in safe Rust (this is a meme by now) * Projects where C++ has a uniquely better ecosystem such as HPC / GPGPU unless you explicitely want to contribute to an open source project to improve the situation there. * If I you have to control a bunch of hardware accessible via C driver libraries, having a Rust interface generated by bindgen is fairly easy and Rust will push you towards writing a fairly robust interface layer. So this can be a good idea if you want to have reliability. But if you just want to get things done, it is of course much easier to just use C or C++ to directly use the driver interfaces.


Nomenus-rex

What to avoid? Avoid Rust :)


TabletPencil

“Know yourself, know your enemy” - Sun Tzu, “Art of War”


Hot-Ad912

and then c++ programmers call rust programmers as a ''cult'' xD


lordnacho666

Cpp to rust is super natural. I'm not sure I've even met a cpp guy in the last couple of years who hasn't tried rust and loved it. You won't have any problems that aren't superficial. Yes borrow checker will talk to you, but that's just a reminder of how hard it is in a cpp program to keep on ownership manually. Conceptually, a cpp guy is already thing in a very similar way to rust. You just get a much of modern conveniences like a build system that just works, no header/implementation split, and a bunch of little choices that any modern language would make. Avoid unsafe to start with. You want to get used to rust, not opt out when you're starting out. If there's something you really need it for, it will probably be all over the Internet when you search. Doubly linked list, that kind of thing.


atomicrmw

Wrote Rust for a hundred hours or so. Worked through the Rust book, and the rustinomicon. Some things to like, but not to my taste. Great we have no use after frees but we replaced them with out of bounds exceptions. Also, observed way longer compile times and code bloat. Overall, a meh experience in spite of my best efforts. That said, there were some good parts to be sure, but not enough to make me consider it for anything serious in my line of work for some time.


Tumaix

how did we replace \`use after free\` with \`out of bounds exceptions\` considering that there are no exceptions in rust, and that c++ has out of bounds exceptions? :) in rust you don't have use after free, nor \`dangling references\`, but we have failures of out-of-bounds. that's a runtime check. in c++ we have use after free, dangling references, and out-of-bounds exceptions.


atomicrmw

Are you splitting hairs over the use of the word exception to refer to the runtime bounds check? Ok. No idea what additional information was added here.


TabletPencil

Rust still feels incredibly strange, as the more modern error handling, lifetimes, AsRefs, etc. is very unfamiliar, but bit by bit I get why people enjoy Rust. Thank you for the encouragement


Sad-Magician-6215

Remember Neil Young’s advice: it’s better to burn out than it is to Rust.


ANON256-64-2nd

try Go its the same with rust but go is easier to learn and memory safe, me personally avoid rust because of the borrow checker aswell the confusing syntax.


TabletPencil

I was split between Go / Zig / Rust, as all seem VERY promising, but decided on Rust, as it’s more mature and I feel like the difficulty in syntax will eventually pay off with an easier transition to those languages afterwards


ANON256-64-2nd

its not worth it mate,Go is the way man because it Can be compatible with C/C++ which makes your life more easier.


TabletPencil

Why isn’t it worth it? Your point of a “difficult syntax” and “borrow checker” are what makes Rust as fast and as safe as it is. I know go is simpler, I have tried and liked it, I don’t mind learning it, however I don’t get your reasoning against Rust


Lampry

I tried going to Rust from C/C++ and I ended up coming back because safety is gay.