4 ms·
C++ can be safe enough if you proceed with care. What I dislike of C++ is that it grew to become a monster of a language, containing all programming paradigms
by DeathArrow 2y ago
C++ can be safe enough if you proceed with care.
What I dislike of C++ is that it grew to become a monster of a language, containing all programming paradigms and ideas, good or bad, known to mankind.
It's so monstrously huge no human can hold its entire complexity in his head.
C++ allows you to do things in 10000 different ways and developer would do just that. Often in the same code base.
That being said, I would use a sane subset of C++ every day over Rust. It's not that I hate Rust or that I don't think is good, technically sound and capable. It just doesn't fit the way I think and I like to work.
I like to keep a simple model in mind. For me, the memory is just a huge array from which we copy data to CPU cache, move some to CPU registers, execute instructions and fetch data from the registers and put it again in some part of that huge array, to be used later. Rust adds a lot of complexity over this simple mental model of mine.
- eptcyka 2y agoWhat complexity specifically does Rust add to that model?
- arnsholt 2y agoI can think of three things off the top of my head: - Rust doesn’t let you pretend that memory is a flat array of bytes - Single ownership of data can be annoying in some cases - The borrow checker pointing out that you’re trying to do something stupid with pointers (again) can be annoying Of course, I’m of the opinion that the hassles are worth it, especially the borrow checker. Almost every time I have to fight the borrow checker, it’s because I haven’t thought properly about the pointers involved and tried to do something stupid.
- eptcyka 2y agoHow does single ownership conflict with the idea that memory is a flat array of bytes? Further, the borrow checker does not care about pointers, only references. With pointers, you are on your own. It is true that using pointers in Rust is more cumbersome than it could be. But it is much easier to compartmentalise the pointer parts into separate functions and expose references instead. I agree that some paradigms and patterns are genuinely difficult to use, e.g. any intrusive data structure, but I do not see the contentious link between simple memory models and the borrow checker and the like.
- arnsholt 2y agoSingle ownership and memory not being flat are separate points. And I guess I'm imprecise saying pointers where I mean borrowed values, but my point is that a borrow is just a pointer with additional type checking. More formally: C pointers are a complete but unsound formal system, whereas Rust borrows are sound but incomplete. And every time I get in a fight with the borrow checker, it's because I'm doing something unsound, not because the system is incomplete.
- kobebrookskC3 2y agoeven in c, you can't assume memory is a flat array of bytes. pointers have provenance, and compilers exploit this: https://godbolt.org/z/ondGh4Ynn https://godbolt.org/z/ondGh4Ynn
- joatmon-snoo 2y ago> if you proceed with care Yes, but that is _incredibly_ time consuming. You have to set up asan, msan, tsan, and valgrind. If you want linting you need to do shenanigans to wire up clang-tidy. I also like simple mental models. I like not having to figure out the cmake modifications to pull in a new library. I like having a search engine when I need a new library for x. I like when libraries return Result<Ok, Err> instead of ping ponging between C libraries which indicate errors using retval flags or C++ libraries that throw std::runtime_error(). I like not dealing with void* pointer casting .
- angra_mainyu 2y agoI find Zig to be a saner Rust alternative, with the caveat that it is still a immature (but getting there). Give it a few years and it will be a very strong contender. The true C successor.
- davemp 2y agoYeah, I’m leaning towards zig but I’m a bit on the fence still. For Rust, I kind of got tired of writing unsafe rust for embedded, but that’s addressable afaik. The real dealbreaker was that after 10k+ lines of code I still will pop open the source of a library that solves a simple problem and the code looks indecipherable. I also don’t really agree with the dependency explosion that cargo encourages. Zig is very nice in that it has the most ergonomic struct usage I’ve encountered. The stdlib could really use some improvement though. Comptime is very cool, but I also worry if the community will get undisciplined with it.
- angra_mainyu 2y agoZig is fantastic, however there are a few issues (mostly related to its immature/wip status): - the build system is constantly changing in a breaking way (between releases some of the repos I have on GH no longer build and need their build.zig to be updated). - the comptime section of the docs needs to be heavily expanded, I'd love to see them take common Go interfaces and redo them in Zig (like io.Writer, io.Reader), breaking down the process step-by-step. It took me a little bit longer than it should've to efficiently use comptime. - a whole section dedicated to things like using WaitGroup and multithreading, for those coming from langs like Go. Also, higher-level concurrency primitives like channels would be fantastic. - a better import system for external zig libraries, the zig fetch => .dependency => .root_module.addImport stuff is not as straightforward as it should be although for someone coming from C it definitely does feel like using meson None of these are critical and again, all signs of Zig's "youth".
- DeathArrow 2y ago>Also, higher-level concurrency primitives like channels would be fantastic. That can be done trough a library.
- ultimaweapon 2y ago> C++ can be safe enough if you proceed with care. The problem with this is if you have a team working on a C++ product you will need some people who can catch memory bugs to review every code before merging. Even with this approach it still possible to missed some memory bugs since the reviewer need to fully understand each object lifetime, which is time consuming during code review. I'm working on a company that run on a server application written in C/C++. The code base is very large and we always have memory bugs that required ASAN on production to fix the bugs. We have started migrating each part to Rust one year ago and we never have a single crash from Rust code. The reason we choose Rust is because it is a server application that computation intensive, latency sensitive and large amount of active connections. Try keep using Rust until you comfortable with it and you will like it. It fit with your simple mental model. I can say this because I was a C++ users for the whole life and switched to Rust recently.
- alexey-salmin 2y ago> The problem with this is if you have a team working on a C++ product you will need some people who can catch memory bugs to review every code before merging. Even with this approach it still possible to missed some memory bugs since the reviewer need to fully understand each object lifetime, which is time consuming during code review. Nah, if you're trying to match every "new" with a "delete" during the code review, you've already lost the battle. You can probably succeed when the code is added, but then the edits start to flow and sooner or later it's gone. Reviews are mostly good to catch design problems, not bugs. The only reliable approach I know is to have a strict rule of never mixing memory management with business logic. Nothing else works well enough but this one however works remarkably well. Business logic should rely on containers, starting with simple unique_ptrs and vectors and going deeper and deeper into the custom land when appropriate. If you can't find a suitable standard container, you build a custom one. The principal difference of "writing a custom container when you need it" compared to "integrate custom memory-management into the business logic when you need it" is that containers are: * well understood * well tested * relatively small code-wise * almost never change once implemented None of the above applies to the business logic, it's the complete opposite. Think of it kind of like programming in Java: someone has to write the memory management and it's a hell of job. However once this is done, programming the ever-changing business logic is easy and safe. You can live the same life in C++ AND also have the ability to put on the "Doomguy of the memory management" shoes whenever you feel like it. Just don't forget to take of the shoes of the "business logic guy" when you do it, you can't wear both at the time.