archives

Some notes on Rust, the language.

Nobody seems be saying much about Rust, or if they are, the LtU search can't find it. So I'm starting a Rust topic.

After some initial use of Mozilla's "Rust" language, a few comments. I'm assumming here some general familiarity with the language.

The ownership system, which is the big innovation, seems usable. The options are single ownership with compile-time checking, or multiple ownership with reference counts. The latter is available in both plain and concurrency-locked form, and you're not allowed to share unlocked data across threads. This part of the language seems to work reasonably well. Some data structures, such as trees with backlinks, do not map well to this model.

There's a temptation to resort to the "unsafe" feature to bypass the single-use compile time checking system. I've seen this in some programs ported from other languages. In particular, allocating a new object and returning a reference to it it from a function is common in C++ but difficult in Rust, because the function doing the allocation doesn't know the expected lifetime of what it returns. It takes some advance planning to live within the single-use paradigm.

Rust's type system is more troublesome. Rust's has most of the bells and whistles of C++, plus some new ones. It's clever, well thought out, sound, and bulky. Declarations are comparable in wordiness to C++. Rust has very powerful compile-time programming; there's a regular expression compiler that runs at compile time. I'm concerned that Rust is starting out at the cruft level it took C++ 20 years to achieve. I shudder to think of what things will be like once the Boost crowd discovers Rust.

The lack of exception handing in Rust forces program design into a form where many functions return "Result" or "Some", which are generic enumeration/variant record types. These must be instantiated with the actual return type. As a result, a rather high percentage of functions in Rust seem to involve generics. There are some rather tortured functional programming forms used to handle errors, such as ".and_then(lambda)". Doing N things in succession, each of which can generate an error, is either verbose (match statement) or obscure ("and_then()"). You get to pick. Or you can just use ".unwrap()", which extracts the value from a Some form and makes a failure fatal. It's tempting to over-use that. There's a macro called "try!(e)", which, if e returns a None value, returns from the enclosing function via a return you can't see in the source code. Such hidden returns are troubling.

All lambdas are closures (this may change), and closures are not plain functions. They can only be passed to functions which accept suitable generic parameters. This is because the closure lifetime has to be decided at compile time. Rust has to do a lot of things in somewhat painful ways because the underlying memory model is quite simple. This is one of those things which will confuse programmers coming from garbage-collected languages. Rust will catch their errors, and the compiler diagnostics are quite good. Rust may exceed the pain threshold of some programmers, though.

Despite the claims in the Rust pre-alpha announcement of lanaguage definition stability, the language changes enough every week or so to break existing programs. This is a classic Mozilla problem; that organization has a track record of deprecating old features in Firefox before the replacement new feature works properly.

Despite all this, Rust is going to be a very important language, because it solves the three big problems of C/C++ that causes crashes and buffer overflows. The three big problems in C/C++ memory management are "How big is it?", "Who owns and deletes it?", and "Who locks it?". C/C++ deals with none of those problems effectively. Rust deals with all of them, without introducing garbage collection or extensive run-time processing. This is a significant advance.

I just hope the Rust crowd doesn't screw up. We need a language like this.