Wednesday, December 27, 2017

My journey to Rust

As most folks who know me already know, I've been in love with Rust language for a few years now and in the last year I've been actively coding in Rust. I wanted to document my journey to how I came to love this programming language, in hope that it will help people to see the value Rust brings to the world of software but if not, it would be nice to have my reason documented for my own sake.

When I started my professional career as a programmer 16 years ago, I knew some C, C++, Java and a bit of x86 assembly but it didn't take long before I completely forgot most of what I knew of C++ and Java, and completely focused on C. There were a few difference reasons that contributed to that:
  • Working with very limited embedded systems (I'm talking 8051) at that time, I quickly became obsessed with performance and C was my best bet if I didn't want to write all my code in assembly.
  • Shortly before I graduated, I got involved in GStreamer project and became a fan of GNOME and Gtk+, all of which at that time was in C. Talking to developers of these projects (who at that time seemed like gods), I learnt how C++ is a bad language and why they write everything in C instead.
  • An year after graduation, I developed a network traffic shaping solution and the core of it was a Linux kernel module, which as you know is almost always done in C. Some years later, I also wrote some device drivers for Linux.
The more C code I wrote over the years, the more I developed this love/hate relationship with it. I just loved the control C gave me but hated the huge responsibility it came with. With experience, I became good at avoiding common mistakes in C, but nobody is perfect and if you can make a mistake, you eventually will. Another reason C didn't seem perfect to me was the lack of high-level constructs in the language itself. Copy&pasting boilerplate to write simple GObjects is nothing most people enjoy. You end up avoiding to organise your code in the best way to spare yourself the trouble of having to write GObjects.

So I've been passively and sometimes actively seeking a better programming language for more than a decade now. I got excited about a few different ones over the years but there was always something very essential missing. The first language I got into was Lisp/Scheme (more specifically Guile) but the lack of type declarations soon started to annoy me a lot. I felt the same after then about all scripting languages, e.g Python. Don't get me wrong, python is a pretty awesome language for specific uses (e.g writing tests, simple apps, quick prototyping etc) but with lack of type declarations, any project larger than 1000 LOCs can quickly become hard to maintain (at least it did for me).

Because of my love for strong-typing, C# and Java did attract me too briefly. Not having to care about memory management in most cases, not only helps developers focus on the actual problems they are solving, it indirectly allows them to avoid making very expensive mistakes with memory management. However, if developer is not managing the memory, it's the machine doing it and in case of these languages, it does that at run time and not compile time. As a C developer and a big hater of waste in general, that is very hard to be convinced of as a good idea.

There was another big problem all these high-level languages: you can't nicely glue them with the C world. Sure you can use libraries written in C from them but the other way around is not a viable option (even if possible). That's why you'll find GNOME apps written in all these languages but you will not find any libraries written in them.

Along came Vala

So along came Vala, which offered features that at that time (2007-2008) were the most important to me:
  • It is a strongly-typed language.
  • It manages the memory for you in most cases but without any run time costs.
  • It's high-level language so you avoid a lot of boilerplate.
  • GNOME was and still is the main target platform of Vala.
  • It compiled to C, so you can write libraries in it and use them from C code as if they were written in C. Because of GObject-introspection, this also means you can use them from other languages too.
Those who know me, will agree that I was die-hard (I'm writing this on Christmas day so that reference was mandatory I guess) fan of Vala for a while. I wrote two projects in Vala and given what I knew then I think it was the right decision. Some people will be quick to point out specific technical issues with Vala but I think those could have been helped. There two other reasons, I ultimately gave up on Vala. The first one was that the general interest in it started to decline after Nokia stopped funding projects using Vala and so did its development.


Hello Rust

But the main reason for giving up was that I saw something better finally becoming a viable option (1.0 release) and gaining adoption in many communities, including GNOME. While Vala had many good qualities I mentioned above, Rust offered even more:
  • Firstly the success of Rust is not entirely dependent on one very specific project or a tiny group of people, even if until now most of the development has been from one company. Ever month, you hear of more communities and companies starting to depend on Rust and that ensure it's success even if Mozilla was to go down (not that I think it's likely) or stopped working on it. i-e "it's too big to fail". If we compare to Vala, the community is a lot bigger. There are conferences and events happening around the world that are entirely focused on Rust and there are books written on Rust. Vala never came anywhere remotely close to that level of popularity.

    When I would mention Vala in job interviews, interviewers would typically have no idea what I'm talking about but when I mention Rust, the typical response is "Oh yes we are interested in trying that out in our company".
  • While Vala is already a safer language than C & C++, you still have null-pointer dereferencing and some other unsafe possibilities. Safety being one of the main focus of the language design, Rust will not allow you to build unsafe code, unless you mark it as such and even then, your possibilities of messing up are limited. Marking unsafe code as such, makes it much easier to find the source of any issues you might have. More over, you usually only write unsafe code to interface with the unsafe C world.

    This is a very important point in my opinion. I really do not want to live in a world where simple human errors are allowed cause disasters.
Admittedly, there are some benefits of Vala over Rust:
  • Ability to easily write GObjects.
  • Creating shared libraries.
However, some people have been working on the former and latter is already possible with some compromise and tricks.


Should we stop writing C/C++ code?

Ideally? Yes! Most definitely, yes. Practically speaking, that is not an option for most existing C/C++ projects out there. I can only imagine the huge amount of resources needed for porting large projects, let alone training existing developers on Rust. Having said that, I'd urge every developer to at least seriously consider writing all new code in Rust rather than C/C++.

Especially if you are writing safety-critical software (people implementing self-driving cars, militaries and space agencies, I'm looking at you!), laziness and mental-inertia are not valid reasons to continue writing potentially unsafe code, no matter how smart and good at C/C++ you think you are. You will eventually make mistake and when you do, lives will be at stake. Think about that please.



I am excited about Rust and I'm hopeful the future is much safer thanks to people behind it. Happy holidays and have a fun and safe 2018!


Anonymous said...

Rust is very interesting, indeed. I have, however, two objections.

1. Rust is not yet "standardised". With that I don't mean necessarily some 900 pages ISO document (345 stating "this page intentionally left blank"), but at least two implementations. If there were a GCC frontend for Rust, you already had me on the boat!

2. Unfortunately, I have to support armel (older ARM processors) for still some years to come. To my knowledge, Rust does not support such CPUs and it would be a little bit tricky to write the support. Still, this is very important to me. For many reasons (including environment and money), I don't want to throw away 2000 devices, worth 2000 Euro each.


zeenix said...

Hi Martin,

Thanks for sharing.

1. While I can understand your reservations here, their relevance depends on what kind of code you are writing. For safety-critical code, I personally would prefer to use tools designed for safety, even if they are not quite standardized. I'm hoping you agree that this point is more to do with personal preferences than anything else so I can only talk about my own preferences. :)

2. That's a good point but are you sure it's not supported already? I see Armv6 listed under Tier-2: . Also ARMv5TE is under Tier-3.

Mattias Bengtsson said...

Martin: the following reddit post might be of interest to you:

It seems like it could be an answer to both of your questions in the future.

Anonymous said...

about 1) Well, almost everything is "safety-critical" nowadays. Anything that has untrusted input can suffer from typical C errors like buffer overflows. From multimedia to an IM app, we need secure code.

My hope for a GCC frontend is this: If there is only one implementation of a programming language, it is more likely, that there will be incompatible changes. I don't want to rewrite all my code every 10 years. (Unfortunately, in free software, API and language stability is not valued much. Both Gnome and KDE force developers to rewrite everything every some years, in web development it is probably some months.) Also, different implementors will find different problems in the language and will solve them. That will make the language more robust for everyone.

about 2) At least in Debian, the armel version did not yet arrive and it seems, that there are some problems: Let's hope, this will be resolved in the coming year...


Moustapha Saad said...


I started to learn/work with C++ 7 years ago and lately i was curious to check Rust.

I tried to code simple programs in rust and I liked:
1) The idea of traits
2) How Rust macros is designed
3) The ease inter-operability with C
4) The whole enum unions and pattern matching

But what made me stick with C++:
1) If the language is using lifetimes it's fine but why i need to help it in some weird cases but let's assume I'm happy to help. the syntax of lifetimes is not that great and i really really don't like it
2) I feel that Rust is not a single language there's Safe-Rust and Unsafe-Rust and i have to learn them both to do anything useful
3) The OSs that i target have a C API and I'm not comfortable with the idea of the two languages as i mentioned above
4) I feel I cannot do anything useful without the help of Rust std library. don't get me wrong Rust std library is great but for example i want to implement a simple linked list then i must use Box. Maybe this is the biggest reason I feel that safe-rust isn't that serious about enabling the programmer to do anything i feel like it's a well designed garden that you shouldn't go outside

at least this is my experience with rust
Thanks for the great post


renoX said...

> Marking unsafe code as such, makes it much easier to find the source of any issues you might have.

Easier, easier.. Think about an API to write and read memory, only the implementation of the API needs to be unsafe but if you make an error in the "safe" part of your code which compute the address, how the distinction between safe and unsafe help you find the error?

dmitry_vk said...

>Think about an API to write and read memory, only the implementation of the API needs to be unsafe but if you make an error in the "safe" part of your code which compute the address, how the distinction between safe and unsafe help you find the error?

What you describe is the failure of a library to validate the safety of "unsafe" code in order to provide "safe" interface. "Safe" here means that the "bad" (data races or memory- or type-unsafe code) will not be executed given _any_ usage of API.

There are certain rules (not enforced by compiler) about meaning of "unsafe". Basically, "unsafe" code should not leak unsafety to its callers under any circumstances.

Anonymous said...

Linked list is not the only one. Even creating a simple thread-safe stack (which usually is done by using atomic CMPX in a loop) has to resort to the unsafe code. From tokio-curl:

Anonymous said...

Mattias Bengtsson: mrustc sounds interesting! So far, it is for x86 only and highly experimental, but maybe it will become a usable alternative to rustc. I would prefer a GCC frontend myself, but the only attempt to write one, died two years ago.

Thanks, Martin

Anonymous said...

> This is a very important point in my opinion. I really do not want to live in a world where simple human errors are allowed cause disasters.

Rust helps to avoid mostly entire classes of memory-management related problems, but there are still thousands of errors an human can commit by mistake even when programming with Rust. For example: errors in the program logic, corner cases not taken into account or tested. No language can shield against that.

Anonymous said...

Nice blog post. In my spare time, I have dealt with Rust a little bit and must say that I like the concepts of the language.

But when it comes to safety critical software things starts to get very tricky. Let's first clarify the meaning of the word safety. In my world the word safety is an abbriviation of the term "functional safety". Functional safety has the objective to reduce the danger to creatures and environment that emanates from a system to a reasonable level. In contrast to that, the word security means to me: "Protection of the system for improper use". There are standards for this kind of safety: IEC61508 or ISO26262 to name two of them.

This standards forces you to qualify each and every tool that you use in your development process of a safety relevant system. And of course this holds true for the compiler you are using to compile code for your safety critical system.

I don't thinks that the rust compiler has such tool qualification yet. Please correct my if I am wrong.

But this compiler qualification alone would be not enough. The whole toolchain from the system specification to system verification and validation (the classical V-model development process as stipulated by ISO26262) with all the needed tools needs to deal with rust and it's compiler.

With that said, nice concepts of a language are simply not enough to get adopted in safety critical projects.