Hacker News new | ask | show | jobs
by mdip 3074 days ago
I'll be an anti-crustangelist and say that I've actually avoided moving a C++ project I've been working on over to Rust because (1) I'm finding that fixing some of the previous code's pre-C++xx practices is suitable enough and (2) I've only written a few small things in Rust up to this point and learning the 30% or so more that I'd need to in order to get things fixed would take more time and has more unknowns. Granted, it's not a large application, the code is easy to follow in its current state, and it wasn't "already a mess" when I started working on it. Fixing its problems has required careful review of the code-base but it was certainly possible and practical to correct the issues with this (small) application; even by someone as weak in C++ as I am[0].

C++ has improved quite a bit, from my perspective, anyway.[1] That said, I'm excited about Rust and have started (shallowly) exploring it. I like what I see, so far; particularly with improvements on the ergonomics of the language. Seeing it put to use in major projects (cough Firefox) successfully and reading about the problems it solved for Mozilla is the main reason I've set a goal to become proficient in it this year. It's a tall order to commit to a new language, particularly when the other languages I write in generally do everything I need them to. There's a small number of things, though, that still pull me toward C++, and I'd rather have an alternative.

As pleasantly surprised as I was with C++, I had plenty of four-letter-word-riddled moments. Practically all of it stemmed from old libraries, or legacy pieces/parts with my favorite being "lets look at the documentation to see what kind of string this method expects/returns". Character encoding, character byte-sizes, differences between byte-length and semantic length are all complexities when dealing with strings -- many of which get hidden away by CLRs or JVMs or script interpreters. And I'm sure there's some reasons that a person with moderate C++ knowledge could tell me as to why so many of the recently developed (proprietary) libraries seemed to love to pass pointers to non-unicode character arrays around (performance? comfort? nationalist? satan worship?), but it was a punch in the face when I knew an "easy" std::string was right there and never needed to be a character array/serve as a buffer/do anything but be a unicode string for a brief moment of existence. And if I have to figure out why Hunter failed to download the boost library because someone statically linked it to cURL without https support, or used the built-in implementation and compiled it with the wrong flags, or for whatever reason, the downloaded version fails the SHA1 check Every. Single. Time. ... well, no need to conclude that one.

Heck, I'd argue crates is a C++ killing feature for me. Yes, Hunter can be made to work (kicking and screaming, sometimes) with cmake, which I'm told can also be made to work. Microsoft has one, too (I can't remember its name and I know they were working on making it possible to just "use NuGet"[3], but I've always felt that a lack of easy dependency retrieval and management caused three problems (1) people use old libraries that are very likely to be present on the target build host, (2) people write their own (poor, naive) implementations for Solved Problems(tm) or (3) the miserable fck doesn't build, there's not enough documentation to figure out in blue-blazes <qwertyuio.h> is, who wrote it and where it came from and when you do* finally find it, it won't build because it's missing its dependencies, so pick (1) or (2) or give up. Compared against '(package-manager) install (package)' and hey, I'm writing code like I originally set out to!

Wow, this devolved pretty quickly into a rant. My apologies for that -- it really isn't as bad as I've made it sound and I realize that most/all of these are my problems and I'm not knocking a language (or folks who program in it) for not bending to my will and having every feature I want, but I'm hopeful for what's coming around with Rust, D and others that are tackling the systems programming space. This Zig article caused me to read several others, as well. The compile-time variables as a workaround for lack-of-macros[3] looks like an interesting idea -- I'm not sure if the syntax is clear enough (globals are implicitly compile-time) but since it's a somewhat unfamiliar syntax, I lack experience to speak intelligently on that.

[0] My adventure started with troubleshooting a very consistent memory leak that was generally caused by some code-in-a-loop that failed to delete things. Often the solution was to change code to use something from boost (which it took a hard dependency on, anyway) or wrapping it in a class and RAIIing my way to a better reality. (and can we get a new acronym? I always write RIAA and if I don't write it, I see it and hairs on my neck stand up)

[1] I "gave up" C++ development around 2001 and short of reading code on rare occasion, didn't seriously start working in the language again until a couple of years ago. I felt like I was writing in a different language -- not sure if that was perception having been away from it for so long, or if it really was that different -- it took a lot of reading to get to a point where I was comfortable breathing in the direction of the code I was playing with.

[2] And NuGet could be a good option, here, especially if they move away from its roots of being somewhat of "it's really just a powershell script with a kludgy metadata file" since I'd rather not add yet another shell to my non-Windows hosts that already have alternatives that I prefer. Last I looked -- .Net Standard pre-2.0, they were fixing the metadata problems -- and maybe they weren't all that bad to begin with considering I can't think of the last time NuGet got in my way on a .Net app.

[3] Though, ideally, I want both.

edit: fix some bad footnote pointers - sheesh, can't even write a comment without a segfault

1 comments

Well, if you want to write a tree using indices in a local array instead of pointers for better locality and memory footprint (which is ideal for many situations), you run into the difference between language pointers and computer science pointers. That's not even something that Rust will be smart enough to help you do properly.
In fact (unless something has changed dramatically without my getting the memo), that's how you would write many data structures in Rust---either for better memory behavior or you have cycles and Rc won't cut it. You have to use a vector of nodes and indices as pointers; if you try using references, the borrow checker comes and kicks sand in your face.
It's doable to keep using pointers instead of indices- they just all have the lifetime of the vector and you can freely follow them around.

This does prevent resizing the vector, but you can get around that by using a different arena that allocates in chunks rather than reallocating (and thus doesn't require a unique reference for .insert).

Rust can totally help you do that properly. You can wrap the indices in a struct parameterized by a lifetime and regain all the same tools you would have with language pointers.