jducoeur: (Default)
jducoeur ([personal profile] jducoeur) wrote2017-04-20 11:30 am
Entry tags:

Rust

This week's adventure in conferencing is my first trip to ScalaDays, which is in Chicago this year. This morning's keynote was a bit surprising, because it was about the language Rust, rather than Scala. But it was a great talk, and very educational -- I've known vaguely of Rust for a while, but really hadn't known the details. Here's a summary of what I learned, but I recommend checking out the video of the talk once it comes out.

I've been a serious evangelist for Scala for a number of years -- my usual take is that it is currently the best language for general, high-level application programming. You can argue the point, but I'm confident about this one: it's a lovely mix of pragmatism, power and principle, and makes programming more efficient and safe.

But -- not all programming is high-level. Some code needs to be closer to the bare metal, for efficiency, access to the hardware, or other reasons -- it needs to be specifically low level. Scala is only now beginning to be able to do this (with the relatively new Scala-Native compiler), and it's yet to be proven in that environment. Rust, on the other hand, is designed for that world from the get-go.

Or to put it another way, Rust is to C++ as Scala is to Java: a much newer, rethought, more powerful and safe language for playing in that domain.

The core problem with low-level systems programming is that it is scary -- it is very easy to commit any of several major mistakes, each of which leads to crashes or, worse, security leaks. This is true even if you're good at this stuff: programs are complex, and the interactions between the parts are where the bugs tend to arise. Rust is all about reducing that fear, and letting you code with confidence.

The beauty of Rust is that they've taken a very principled look at where those problems tend to come from, and found a few key areas to improve. In particular, the observation is that many bugs arise from uncontrolled access to memory. Plain and simply, pointers are a problem.

So Rust's biggest innovation is removing that word "uncontrolled". It introduces a compiler-time notion of "ownership", and distinct notions of mutable references (which give a code block the right to alter that memory block) vs "shared" references (which allow you to inspect the memory). While they don't use the same terminology, the concepts appear to be quite similar to write vs read locks in database programming.

They've built a lot of infrastructure on top of that, with some really remarkable results. Perhaps most impressive, they've built a concurrency framework that manages to be both flexible and safe. Most of the standard patterns for concurrent programming exist, but they're all adjusted to this ownership-centric world, such that many of the common race-condition problems just can't arise unless you explicitly say "yes, this code is cheating -- I know what I'm doing".

It doesn't solve every problem -- I checked after the talk, and confirmed that it's totally easy to cause deadlocks (unsurprising, given how much this looks like database programming) -- but it's still beautiful and powerful. In the area of concurrent programming, Rust is arguably better than most high-level languages.

Overall, I'm impressed, and I'm pleased to see Rust being presented at a Scala conference -- it looks to me like the languages are nicely complementary. Rust isn't really in competition with Scala: it is optimized for different kinds of problems. But it is principled, and well-designed, in a way that is very reminiscent of Scala. The combination of Scala for application-level programming with Rust for systems and components provides a solid replacement for the older Java/C++ stack.

Not that I've done much systems programming in the past 15 years, so I don't know if I'm likely to use Rust any time soon. But it's good to see the rise of a language that doesn't suck for that domain. God knows, my life 20 years ago would have been much happier with it...

hudebnik: (teacher-mode)

[personal profile] hudebnik 2017-04-22 03:41 am (UTC)(link)
No, and I'm pretty sure it never will; almost any way to do that would break millions of lines of legacy code.

Note: I said "C++ got *tolerable* while I wasn't looking," not "C++ got clean and elegant while I wasn't looking" :-)

That said, I suspect the run-time overhead of passing a unique_ptr as opposed to an ordinary pointer is minimal: the compiler can tell at compile time that this is what you're doing, so it generates an extra "set pointer to null" instruction, which isn't much of a price to pay on top of the parameter-passing and function-calling you were already doing. The real loss in doing it at run-time rather than compile-time is informative and early error messages.

There are also disadvantages to the compile-time approach. For example,

unique_ptr blah = MakeUnique(3);
while (complex condition that never happens) {
foo(std::move(blah));
}
// is blah valid here?

A compiler has to assume, pessimistically, that the condition actually happens at least once, and answer "no". A run-time library can wait to see whether foo is actually called on blah before invalidating it, and answer "yes".