Rust as a productive high-level language

Rust is often critiqued as a not a very productive programming language. It is true that there is a bit of a learning curve to be able to program in Rust; but beyond that, I think it pays off in productivity; and massively I must say.

I haven't been using Rust for production much; maybe a bit more than a year. The static type checks means I'm getting much less bugs in my code, and spend considerably less time in debugging. I can safely say that, for me, Rust is more productive than JavaScript, PHP or Python and the margin keeps getting larger as I get more acquainted with the ecosystem.

To entice your interest, here is a situation that I handled lately: I have a program that writes logs to syslog and the terminal. The program compiles and functions correctly on my development machine. However, it returned an error when I deployed it to an Alpine Docker container. Turns out, Alpine doesn't have a running syslog service by default.

Now that's fine, the program functioned correctly. But I don't care much for syslog on deployment since the program is running inside a container. One solution is to remove the syslog drain but I need that for development. I can use conditional compilation; but there is a better option: If syslog fails, for whatever reason, just ignore that and move on.

So let's take a look at the old code.

let syslog_drain = syslog_drain()?;
let term_drain = term_drain()?;

This code creates two logging drains: one for syslog and one for the terminal. It uses the ? operator to evaluate the result. If the function returns an error, execution will stop and the error bubbles back to the top of the program.

I have no idea how the syslog or any particular drain fails. And honestly, I don't want to get into these details. What I want is to check if there is a failure; and if so ignore that particular drain. Or return a Discard drain.

The Result type and ? operator make this particularly easy. So here is the code that does that.

let syslog_drain = syslog_drain().unwrap_or(discard_drain()?);
let term_drain = term_drain().unwrap_or(discard_drain()?);

And that's it. This code now compiles and runs correctly. If syslog is running, it'll write logs to syslog and the terminal. Otherwise, it'll write logs to the terminal and syslog is skipped. There are no conditions, no complicated checks and it's perfectly readable.

There is more to Rust productivity than that. Macros, Iterators, Advanced Traits and Types, the new Async system. Once you are comfortable with all of these, you are now able to be productive, safe and fast.

Published on