1. 22

  2. 32

    it’s still no match for easy-entry languages like Python or Go. But learning it is a one-time cost. Contrast this with Go, where you may find the apparent simplicity is only skin-deep.

    Thanks, I wish people would be more vocal about this. The “hard” part of Rust is learning the language, the hard part of so many other languages is learning the quirks and bad design decisions. You learn the former upfront, you learn the latter from incidents.

    1. 3

      I don’t know. I have a static site generator that I ported from Python to Go to Rust and now back to Go. The first three were just ways to explore new languages, but the final iteration was “I actually use this, and the Rust version is really hard to maintain” (specifically, despite being more elegant and performant, adding functionality was so much more cumbersome for minimal benefit even as someone who knows Rust pretty well by now).

      Additionally, I made more mistakes writing the Rust version than the first Go version despite having the benefit of hindsight and a robust type system. I flubbed some filepath/URL manipulation code in large part because I was so focused on the type system (making decisions about borrowing vs cloning).

      In a separate project, I was dealing with a lot of integer IDs which identified different kinds of resources—in order to make sure I used the right ID for the right resource type, I wanted to create an integer newtype (struct FooID(u64)), but there was a lot of tedium in making all of the necessary arithmetic and conversion traits to have something that was basically usable as an integral type and I still had a couple of frustrations: (1) I still couldn’t automatically instantiate a typed variable from an integer literal a la Go’s x = 0; rather, I had to type x = FooID::new(0) or x = 0.into() or similar and (2) I couldn’t use those arithmetic traits in const contexts, so I had to define a bunch of const functions with similar names. Go just kind of does what I want out of the box—it doesn’t let me implicitly convert between types, it lets me do const arithmetic, and I can instantiate variables from untyped integer constants. If I had to do it again, I’d be tempted just to use u64s for everything (I’ve seen quite a few projects do the same, but I’m not sure which approach is idiomatic), but this is definitely going to yield more bugs.

      1. 2

        I’m glad to hear that you found a good tool for your job. So do you feel that you can write robust misuse-resistant interfaces in Go? What are your techniques for achieving this?

        1. 2

          I’m not sure what you mean. I don’t have many problems with people misusing code. Usually the type annotation makes usage pretty obvious and where it isn’t obvious, I add a small, precise, clear comment. Mostly though I try to keep my interfaces as simple as possible.

          I’m not saying Go is perfect; const and Rusty enums would be great, and I would love better compiler optimizations. But Go is just wildly more productive than Rust for most applications in my experience (productivity is not always the most paramount concern either).

          1. 2

            Yeah, when I wrote some Go, I was missing enums dearly. Also the ? operator; the error handling gets quite wordy. I still think that it’s mostly down to familiarity: Having written Rust code for some time, I can now write stuff in Rust faster than I could in Go, while I allege that someone who’s more fluent in Go will have a contrary experience.

            1. 1

              I don’t think it’s just fluency. I’m wayyy more versed in Rust than say TypeScript (like nearly 10 years more experienced), but I’m wayyy more productive in TypeScript. I agree that error handling in Go is more verbose than in Rust if you’re not adding context to your errors, but I prefer to add context for debugability (fmt.Errorf(“doing foo: %w”, err)). You can do this in Rust with anyhow but that seems like bad practice for library code. Further, I spend a lot of time in Rust crafting error enums and setting up the necessary traits (including convenience traits like From). thiserror helps but I still find myself fighting compilation errors in the generated output. Similarly, I also agree that Rust enums would be nice in Go, but unless I’m writing a compiler or something that is just enums all the way down, I just make a struct with a tag field or use interfaces and move on with life (definitely a loss of safety, but I can move so much faster than with Rust that I have plenty of time to test).

        2. 2

          in order to make sure I used the right ID for the right resource type, I wanted to create an integer newtype (struct FooID(u64)), but there was a lot of tedium in making all of the necessary arithmetic and conversion traits

          I don’t want to push you to return to Rust if you didn’t like it, but I think this is a use-case for ambassador (or delegation, the non-existent built-in equivalent). (Using a procedural macro like ambassador surely will not reduce the difference between Go’s and Rust’s compilation speeds, though….)

          I don’t think I understand why one would want integer newtypes used as IDs to support arithmetic, though.

          1. 2

            I should note that I still like Rust; I just don’t relate to some of the comparisons with Go. Specifically, Rust is great for systems programming or high performance programming; basically stuff where C and C++ is used today. I also like Rust in theory—the emphasis on zero-cost abstraction and so on.

            1. 1

              A filesystem needs to convert between block numbers and byte offsets and so on.

              1. 1

                Ah, I had been thinking of otherwise meaningless identifiers (such as mio::Token, id_arena::Id, and a number of types in Salsa).

        3. 11

          Very the same experience at Quickwit, and coincidentally a search engine too (but no vector here).

          My cofounder Paul started Tantivy, a Lucene-like library years ago, it was just a pet project in Rust. He was a very experienced developer in Java and C++ (around 10 years of XP) and wanted to give a try to a language that allows low-level control such as C++. In two weeks, he was more productive in Rust…

          As for myself, very often (I can’t say every day because I have to code in typescript and go for plugins stuff…), I thank the compiler for pointing me my mistake or inaccuracies. It is hard but you have immediate feedback and you can learn fast. Before starting Quickwit, I wrote mostly in Python. Today I can tell you that I sleep way better when we ship something in production :)

          1. 8

            Python is not a bit younger than Java, it’s the other way around. Python 0.9.0 came out in 1991 and Java 1.0 alpha came out in 1994.

            1. 2

              Well, Python 1.0 also came out in ‘94, and Java was called Oak before being renamed to the hot brew we all know and love. But I’ll gladly admit one could argue either way.

            2. 3

              Somebody is very excited about Rust!