Rust: A Critical Retrospective

This page summarizes the projects mentioned and recommended in the original post on news.ycombinator.com

Our great sponsors
  • SonarQube - Static code analysis for 29 languages.
  • Scout APM - Less time debugging, more time building
  • JetBrains - Developer Ecosystem Survey 2022
  • rust

    Empowering everyone to build reliable and efficient software.

    You were allowed to have arrays longer than 32 elements, but dealing with them was hard. Beyond Copy trait, which is a compiler builtin, many traits weren't implemented for arrays with more than 32 elements.

    The first such change was implemented in 1.47.0 in 2020: https://github.com/rust-lang/rust/blob/master/RELEASES.md#ve...

    But it took a few releases, until 1.51.0 in 2021, until custom traits could be implemented for arrays of any length: https://github.com/rust-lang/rust/blob/master/RELEASES.md#ve...

    And the feature is still limited. For example, legacy users like serde still can't switch to the new const generics based approach, because of the same issue that the Default trait is facing.

  • warp_like_express

    Incomplete ExpressJS-like Rust server that runs on Node.js natively

    I experimented with replacing an Express server with Rust while keeping the same js syntax and still running on Node

    Granted this adds overhead, but my conclusion was that the performance gain is not worth the effort. Sure, memory looks almost flat but response times aren't that much better

    https://github.com/javieranton-zz/warp_like_express

  • SonarQube

    Static code analysis for 29 languages.. Your projects are multi-language. So is SonarQube analysis. Find Bugs, Vulnerabilities, Security Hotspots, and Code Smells so you can release quality code every time. Get started analyzing your projects today for free.

  • Rustup

    The Rust toolchain installer

  • regex-automata

    A low level regular expression library that uses deterministic finite automata.

    (I could use '_ => {}' instead of 'None' to save a few more.)

    I do find the 'if let' variant to be a bit easier to read. It's optimizing for a particular and somewhat common case, so it does of course overlap with 'match'. But I don't find this particular overlap to be too bad. It's usually pretty clear when to use one vs the other.

    But like I said, I could live without 'if let'. It is not a major quality of life enhancement to me. Neither will its impending extensions. i.e., 'if let pattern = foo && some_booolean_condition {'.

    [1]: https://github.com/BurntSushi/regex-automata/blob/fbae906823...

    [2]: https://github.com/BurntSushi/regex-automata/blob/fbae906823...

  • biscuit

    Biscuit research OS

    Go has been used to implement OS kernel code, e.g. in the Biscuit OS from MIT: https://github.com/mit-pdos/biscuit

    Of course, the garbage collector did not exactly make it easier - but it's an interesting piece of software.

  • jnode

    Code for the JNode operating system (by jnode)

    Go has been used to implement OS kernel code,

    but it's an interesting piece of software.

    Agreed. And I didn't mean to imply that it's impossible to use Go that way, but I think it's fair to say that it's less common and perhaps even less desirable to do that.

    OTOH, people have written (at least parts of) Operating Systems in Java[1] even, so never say never...

    [1]: https://github.com/jnode/jnode

  • trycmd

    Snapshot testing for a herd of CLI tests

    I find rustdoc lacking for clap. rustdoc does a good job with API reference documentation and is improving in its handling of examples but derive reference and tutorial documentation are a weak point.

    For examples, its improving with the example scraping work (e.g. https://docs.rs/clap/latest/clap/struct.ArgMatches.html#meth...) but testing of example is still lacking. I've written trycmd to help (https://github.com/assert-rs/trycmd).

    For derive reference and tutorial documentation, your choices are

    - A very long, hard to navigate top-level documentation, see https://docs.rs/structopt/latest/structopt/

    - External documentation, see https://serde.rs/

    - Dummy modules to store your documentation (I've seen this used but can't remember one off the top of my head)

    For clap, my documentation examples are best served as programs and we've had a problem with these being broken. The Rust CLI book has a decent strategy for this by pulling in code from external files (https://rust-cli.github.io/book/index.html). I was tempted to do that for clap where example code and output (all verified via trycmd) are pulled into an mdbook site but I've stopped short and just have a README that links out to everything (https://github.com/clap-rs/clap/blob/master/examples/tutoria...). Its not great.

  • Scout APM

    Less time debugging, more time building. Scout APM allows you to find and fix performance issues with no hassle. Now with error monitoring and external services monitoring, Scout is a developer's best friend when it comes to application development.

  • serde

    Serialization framework for Rust

    I find rustdoc lacking for clap. rustdoc does a good job with API reference documentation and is improving in its handling of examples but derive reference and tutorial documentation are a weak point.

    For examples, its improving with the example scraping work (e.g. https://docs.rs/clap/latest/clap/struct.ArgMatches.html#meth...) but testing of example is still lacking. I've written trycmd to help (https://github.com/assert-rs/trycmd).

    For derive reference and tutorial documentation, your choices are

    - A very long, hard to navigate top-level documentation, see https://docs.rs/structopt/latest/structopt/

    - External documentation, see https://serde.rs/

    - Dummy modules to store your documentation (I've seen this used but can't remember one off the top of my head)

    For clap, my documentation examples are best served as programs and we've had a problem with these being broken. The Rust CLI book has a decent strategy for this by pulling in code from external files (https://rust-cli.github.io/book/index.html). I was tempted to do that for clap where example code and output (all verified via trycmd) are pulled into an mdbook site but I've stopped short and just have a README that links out to everything (https://github.com/clap-rs/clap/blob/master/examples/tutoria...). Its not great.

  • clap-rs

    A full featured, fast Command Line Argument Parser for Rust

    I find rustdoc lacking for clap. rustdoc does a good job with API reference documentation and is improving in its handling of examples but derive reference and tutorial documentation are a weak point.

    For examples, its improving with the example scraping work (e.g. https://docs.rs/clap/latest/clap/struct.ArgMatches.html#meth...) but testing of example is still lacking. I've written trycmd to help (https://github.com/assert-rs/trycmd).

    For derive reference and tutorial documentation, your choices are

    - A very long, hard to navigate top-level documentation, see https://docs.rs/structopt/latest/structopt/

    - External documentation, see https://serde.rs/

    - Dummy modules to store your documentation (I've seen this used but can't remember one off the top of my head)

    For clap, my documentation examples are best served as programs and we've had a problem with these being broken. The Rust CLI book has a decent strategy for this by pulling in code from external files (https://rust-cli.github.io/book/index.html). I was tempted to do that for clap where example code and output (all verified via trycmd) are pulled into an mdbook site but I've stopped short and just have a README that links out to everything (https://github.com/clap-rs/clap/blob/master/examples/tutoria...). Its not great.

  • gccrs

    GCC Front-End for Rust

    Yeah I mean this is still kind of the case today, Rust just avoids it because there is really only one reference implementation. That may not even be true forever, Rust on GCC is continuing to get more and more feature complete over time. [1][2]

    Take the "defer" keyword in GNU C - it's valid in anything that has the GNU extensions but isn't standard C at all. And yet, some projects swear by it (it's not a bad feature, just nonstandard).

    There's a lot of weirdness in C implementations even looking across LLVM, GNU, or even when picking which libc you want! Try porting any nontrivial project to work with musl-libc. You might find that it's not as easy as swapping in a target and building statically!

    This is perhaps the whole rub with standardization - it's bought us as developers a lot, but it doesn't cover everything. The veil was kind of lifted for me when I started trying to use different Scheme implementations in a "standardized" way. I eventually gave up on that and just use whatever implementation I am most happy with (often CHICKEN, but that's a digression).

    This gets more complicated with C++, which modern standards mostly requires C11, but then also doesn't support everything that C11 requires either. They're different languages but yeah, compilers are gonna disagree on some of the edges there.

    [1] https://github.com/Rust-GCC/gccrs

    [2] tangentially, Rust also avoids some UB discussion because the type system is a bit more complete in terms of its properties than C is, so they can resort to Option or Result when things get dicey in an API. Further, there's no official Rust ABI unlike C, so you don't have to worry about that either...

  • steam-for-linux

    Issue tracking for the Steam for Linux beta client

    > Problems like removing a large directory instead of a file

    rm doens't do that unless you explicitly tell it to.

    > Problems like removing a large directory instead of a file, creating your files on random places instead of the directory you pass on, or creating more files than you intended?

    But yes, all of these can and do exist in other languages. Using python as an example, if you read an environment variable without checking it's set (as in the infamous steam bug) [0], you'll end up with pretty much the exact same behaviour. You can misindent your loop in python and not create/remove files that you intend to, or your script can have a syntax error halfway through and the interpreter will happily proceed until it halts, and leave you in a half baked state just like bash does.

    [0] https://github.com/valvesoftware/steam-for-linux/issues/3671

  • rust

    Empowering everyone to build reliable and efficient software. (by betrusted-io)

    This is correct.

    When you tell someone to install Rust, they go to rustup.rs and install the latest version. Therefore, we need to have a libstd port for the latest version. Which effectively means we need to release libstd as soon as possible after the compiler is released. Our `sys` directory is at https://github.com/betrusted-io/rust/tree/1.61.0-xous/librar... and isn't too complicated. It's about 50 patches that need to be carried forward every six weeks.

    Fortunately libstd doesn't change too much, at leaset not the parts we need. And I can usually pre-port the patches by applying them to `beta`, which means the patches against the release version usually apply cleanly.

    It's still better than requiring nightly, which has absolutely no stability guarantees. By targeting stable, we don't run into issues of bitrot where we accidentally rely on features that have been removed. Rather than adjusting every service in the operating system, we just need to port one library: libstd

    I've considered trying to upstream these, but I'm not sure how the rust team would feel about it.

  • heapless

    Heapless, `static` friendly data structures

    > we did not have Vec because we were no-std + stable so we literally had to use arrays

    It's true that Vec isn't available in a no-std context, but don't think it follows that arrays are the only other option - see heapless for one example: https://github.com/japaric/heapless

    I also agree with some of the ancestors: the post seems to say that the Rust language couldn't handle arrays with more than 32 elements, and (as someone who's written a fair bit of no-std Rust before const generic) that doesn't seem right. At first, this did seem awkward to me as well, but in practice I haven't found it to be a significant limitation. Was there a particular scenario where it wasn't feasible to wrap a >32 element array in your own type and implement Default on it?

  • KEEP

    Kotlin Evolution and Enhancement Process

    Kotlin has value classes. Here's a good overview of how they work in Kotlin: https://github.com/Kotlin/KEEP/blob/master/notes/value-class...

    That document is a few years old now and was intended as a design document. But Value classes shipped with Kotlin 1.5. Apparently they are compatible with the project Valhalla value objects that will be added to the JVM at some point. So, this stuff is coming.

    I had to look it up because even though I write Kotlin a lot, value classes are not something I have used at all. Looks useful but not that big of a deal and doesn't really solve a problem I have. Data classes and records (in Java) are a bigger deal IMHO.

    In practice, the way you deal with immutability in Kotlin is to keep most of your data structures immutable by default unless they need to be mutable. E.g. there's a List and a MutableList interface. Most lists are immutable unless you create a MutableList. Same with val vs. var variables. Val variables can't be reassigned and you kind of use var only by exception when you really have to. The compiler will actually warn you if you do it without good reason. A data class with only vals can't be modified. Java is a bit more sloppy when it comes to mutability semantics. It has records now but all the fields have setters by default. It has var but no val assignments (you can use final to force this but few people do). And so on.

    Semantically this is not as strong as what Rust does of course but it's good enough to make e.g. concurrency a lot easier. Mostly, if you avoid having a lot of mutable shared state, that becomes a lot easier.

    You could imagine a Kotlin like language with much stronger semantics implementing borrow checking instead of garbage collection. It wouldn't be the same language of course but I don't think it needs to be very different. Using it would not be a massively different.

NOTE: The number of mentions on this list indicates mentions on common posts plus user suggested alternatives. Hence, a higher number means a more popular project.

Suggest a related project

Related posts