Rust 2020

This is κeen. Here is my thoughts on Rust 2020. Though I’m a Japanese speaker, and I don’t think the Rust Developers accept only English-written blog posts, I write this post for non-Japanese speakers.

Here I describe my personal experience with Rust. I have written Rust for 3 years in daily office work to develop a Web service (actcast.io), which consists of about 60k lines of Rust codes. I feel Rust is enough expressive to write web applications (especially with async/await). We published a 600 pages of book about Rust in May, which fully supports Rust 2018. I guess this is the world’s first book written about Rust 2018!. And I use Rust for most of my hobby programming, such as writing compilers. My compiler targets WebAssembly and runtime is also written in Rust. Thanks to neat WASM support of Rust, I managed to write entire system in Rust. Rust is great!

Here is my wish list for Rust 2020. In a nut shell:

  • I’m happy with Rust
  • Error handling is not awesome
  • RLS should utilize multicore
  • I want some ergonomic features of the language

First of all, I thank all of the Rust Developers for finishing the work of async/await. As I wrote, we have successfully migrated to futures 0.3 and async/await, which greatly simplified our application. To say more, we have smoothly migrated Rust 2018 edition thanks to the great tool cargo fix.

I’m happy with Rust in most of cases. However, there are some pain points of Rust.

There are some variants of error handling. Though I prefer to use std::error::Error because it’s standard, some libraries require failure, and some other libraries require other error handling crates. It’s okay because diversity is good. However, when you combine some of these crates, you’ll have a nightmare. You need to learn all of these error handling. You need to write compatibility codes for the variants of errors. During that, some of information (like backtrace) drops when converting one error to another style of error. I guess fix the error trait resolves some of these problems. BTW, I haven’t heard about try block for a while. I wish it will be done in Rust 2018 edition.

One more pain point is RLS. In the view of features, it works fine. It helps me to knowning the type and documentation of items, it suggests completion for me. However, it doesn’t work with multicore. I have 16-core machine for buildng Rust programs (because Rust needs machine power to build), but RLS doesn’t utilize the available resources. RLS blocks me from writing codes fluently in the scale of our project. It extremely slows down when I edit comments and string literals but I haven’t mutch investigated whethe the cause is RLS or Emacs’s lsp-mode. I guess parallelizing RLS means pararllelizing rustc. In that sence, my wish is parallelizing rustc.

To mention language specifications, I feel some of features lack affinity.

While Rust supports fluent writing of method chains (and .await), some API requires applying 1-arity functions (like Ok, Box::new), which forces the user to back to the head of expression and enclose the entire expression with parens. It’s cumbersome. I want some neat syntax sugar of such application, say, pipe operator (|>) like in F#. To say more, I’d like to write long_expression |> return; rather writing return long_expression;, but as it complicates the specification I don’t wish so far.

I’d like for traits and related features to be more flexible. In our project, which is relatively large, we split the application into some crates. Data definitions and codes using them are decoupled. In such situations, you cannot implement external traits to data types. For instance, we have a generic data type which shouldn’t depend on anything and a code that use it with diesel. Diesel provides derive macros, but you cannot apply the derive macro to the data type because it’s definition isn’t here. To use derive macro, we need to rewrite the data definition and write convertion codes between this definition and the other definiiton. It’s cumbersome.

The last thing is match ing against Box. When you write a compiler you often need to write Box<Expr>s, like enum Expr { Add { l: Box<Expr>, r: Box<Expr>}}. With Expr enveloped in Box, you cannot write nested patterns to match against it. To address this problem, there are some options.

  • Treat Box specially. Automatically deref it
    • You may want to apply that rule to Rc, Arc, etc.
  • Introduce view patterns or pattern guards like in Haskell (GHC).

I don’t care which of those adopted, or even other methods are wellcome. I merely want the problem fixed.

Lastly I thank the Rust Developer and all the community members again.

Written by κeen