Contents

Learning rust as a C++/python programmer (advent of code 2021)

This year I used rust to do advent of code (AoC). I got up to day 17 before Christmas caught up with me, but I hope to come back to the last week at some point soon. Here’s my code so far: https://github.com/johnlees/advent-of-code-2021.

I’ve never done any rust programming before, so started off by reading these two pages which got me going fairly quickly:

At the moment I usually code in C++ and python (and increasingly CUDA), though I do know a few other languages to various levels. rust is a systems language, is compiled, and is statically typed so I expected it to be similar to C++. But it’s less encumbered by the history/backward-compatibility of C/C++, and sometimes feels a bit more like writing python, which can be quite nice.

Overall I did enjoy using rust, and for the style of the problems in AoC I thought it was definitely easier to get going with than C++. I also thought that the guards against segfaults and the like seemed like they would be very useful for scientific code.

However, I’m quite tied into C++ now due to its interoperability with python and CUDA, and certainly still feel more confident at it than rust. So for now I don’t see myself doing my next project in rust – unless it’s a WebAssembly project, in which case I’ll certainly be using rust, as it looks like this should work very easily compared to C++.

Some more specific thoughts comparing rust with C++ below.

Good

  • Vectors having bounds checks on by default, and more generally stopping you working with uninitialised/moved memory seems very useful, particularly for scientific programming/research software. Although I try to run my C++ programs through valgrind to catch these things, I must admit I don’t have this set up in CI workflows, don’t test all code pathways, and with big libraries interacting with python it can become quite hard. rust stops a lot of these issues occurring in the first place, and I can see this making a) more stable software and b) getting fewer github issues with ‘segmentation fault’ which are very difficult to replicate and fix.
  • The default for many assignment operators being move rather than copy. Large copies of vectors have caught me out many times in C++, and this is avoided. Also as moves are tracked, rust stops you using an object which has been moved.
  • The vscode integration was very good. I basically never reached the compiler with errors as the squiggles worked so well. As soon as you use dependencies in C++ this becomes difficult to get working.
  • auto is basically the default type in rust, which is sensible. Easy to override too.
  • Fixed width integer and real types. I hate long long etc and all the implementation/platform specific definitions. I try to use uint64_t etc in C++, but sometimes I forget. That these are all explicit in rust is very good (except for usize but this also has a more sensible definition imo).
  • In rust you have to write mut if you want to change a variable. In C++ you have to remember to write const if you want a variable to not be changed. The rust approach is better I think, as it’s so easy to forget const, and making you think about mutability is often helpful.
  • The crate system seemed very good. Packaging is non-existent in C++ and it makes barrier to entry quite high. If you’ve got a header-only library or can manage things via conda it works ok (I actually stopped using C++ for a few years before I worked conda out, as supporting compiled dependencies in scientific software just became too hard). But in my use of rust so far I’ve just add the crate name to the config file and it all just worked really easily.
  • Compiling was a doddle. cargo run and it does it all! I also appreciated that you get a debug build by default, and it’s easy to then make a release build when you need it. I think the use of Makefiles/CMake means C++ is a lot more of a pain to get going with (both for new and experienced developers).
  • Default HashMap looks a lot better than C++ unordered_map.
  • Regex support was basically identical to python, very impressed by that for a compiled language (still worse than perl, but what can you do).

Neutral

  • In rust you have to explicitly take the address when you pass by reference to a function, in C++ it’s implicit. Not sure which is best.
  • &mut x was quite ugly to me as it looks like you’re taking the address of a keyword.
  • I had more battles with usize <- > i32/i64 conversions than I’d have liked, and the casting between them is a lot more heavy-handed. I suspect you’d get used to this when in the habit of using the correct type in the first place, but I feel like C++ gets in my way less on this issue where I’m fairly confident I know what I’m doing.
  • The FFI looks promising, but I haven’t used it yet.
  • The Option struct is a nice way of implementing the very convenient None type which is so useful in interpreted languages. Learning to .unwrap() was a bit of an uphill battle, and I wondered if it might be overused in some libraries.
  • Objects. Personally I’m very tied in with the way C++ objects work, and it’s a nice way to work between languages. Simple structs with some methods worked nicely, but I ran into issues when trying to use some of the overrides for e.g. Index and IndexMut. This might just be inexperience though.
  • As cargo did everything for me I learnt nothing about the rust compiler rustc. Not a problem for now as I didn’t need to learn. But if there are differences in compiling and linking compared to gcc and clang I would be less confident in using and debugging it more manually in a larger project.
  • I’m very familiar with g++ compiler error messages and how to fix them now. The rustc ones are clearer so far, but I didn’t get into templating, so not sure whether things are better or worse there.
  • C++ has OpenMP, which I think is great. Rust has rayon, which I haven’t tried yet. It looks more like parallelism in e.g. R, but with some more flexibility.

Bad

  • No CUDA support (this will of course not matter at all for many people).
  • Python/Cython bindings less advanced than C++ equivalents.
  • It’s a newer language, so there are fewer stackoverflow hits for your issues.
  • Documentation is less good than C++ I think. Compare rust’s Vec and C++’s std::vector. I presume the rust one is being autogenerated with doxygen or something similar, but the various tiers of methods and inheritance often made it hard to find the function I needed with an example.
  • Templates (generics in rust) seemed a lot more fiddly, and I was not successfully able to template a return type of a function, which was very frustrating.
  • Now having done some lower level stuff of pointer casting and memory alignment in C++, my understanding is that this would be a bit more difficult in rust (but still possible with an unsafe block).
  • I didn’t like ndarray as much as Eigen or numpy, it was definitely more difficult to learn and use.
  • rust’s String class was very fiddly in my opinion and I found doing anything other than trivial string manipulation was a bit of a faff. The basic problem I had was that the class uses UTF-8 rather than 8-bit ASCII by default, which makes slicing and indexing painful. Being able to put emojis in the code and terminal output was fun (and perhaps sometimes even useful), but for my uses the costs definitely outweighed the benefits. [I appreciate that for language support this feature might be great, but I’ve never used UTF-8 in any other programming language before]