Was Rust Worth It?

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

Our great sponsors
  • WorkOS - The modern identity platform for B2B SaaS
  • InfluxDB - Power Real-Time Data Analytics at Scale
  • SaaSHub - Software Alternatives and Reviews
  • Vrmac

    Vrmac Graphics, a cross-platform graphics library for .NET. Supports 3D, 2D, and accelerated video playback. Works on Windows 10 and Raspberry Pi4.

  • > Part of Panama

    Most real-live C APIs are using function pointers and/or complicated data structures. Here’s couple real-life examples defined by Linux kernel developers who made V4L2 API: [0], [1] The first of them contains a union in C version, i.e. different structures are at the same memory addresses. Note C# delivers the level of usability similar to C or C++: we simply define structures, and access these fields. Not sure this is gonna be easy in Java even after all these proposals arrive.

    For a managed runtime, unmanaged interop is a huge feature which affects all levels of the stack: type system in the language for value types, GC to be able to temporarily pin objects passed to native code (making copies is prohibitively slow for use cases like video processing), code generator to convert managed delegates to C function pointers and vice versa, error handling to automatically convert between exceptions and integer status codes at the API boundary, and more. Gonna be very hard to add into the existing language like Java.

    > "Vector API" JEP

    That API is not good. They don’t expose hardware instructions, instead they have invented some platform-agnostic API and implemented graceful degradation.

    This means the applicability is likely to be limited to pure vertical operations processing FP32 or FP64 numbers. The rest of the SIMD instructions are too different between architectures. A simple example in C++ is [2], see [3] for the context. That example is trivial to port to modern C#, but impossible to port to Java even after the proposed changes. The key part of the implementation is psadbw instruction, which is very specific to SSE2/AVX2 and these vector APIs don’t have an equivalent. Apart from reduction, other problematic operations are shuffles, saturating integer math, and some memory access patterns (gathers in AVX2, transposed loads/stores on NEON).

    > most of these are not done / not in a stable LTS Java release yet

    BTW, SIMD intrinsics arrived to C# in 2019 (.NET Core 3.0 released in 2019), and unmanaged interop support is available since the very first 1.0 version.

    [0] https://github.com/Const-me/Vrmac/blob/master/VrmacVideo/Lin...

    [1] https://github.com/Const-me/Vrmac/blob/master/VrmacVideo/Lin...

    [2] https://gist.github.com/Const-me/3ade77faad47f0fbb0538965ae7...

    [3] https://news.ycombinator.com/item?id=36618344

  • Composer

    Dependency Manager for PHP

  • WorkOS

    The modern identity platform for B2B SaaS. The APIs are flexible and easy-to-use, supporting authentication, user identity, and complex enterprise features like SSO and SCIM provisioning.

    WorkOS logo
  • Packagist

    Package Repository Website - try https://packagist.com if you need your own -

  • Sorta—it looks like they were most enforced by convention until May 2015, when they finally become enforced [0]. Still, that's a good one that I hadn't thought of, and they at least had the convention in place.

    [0] https://github.com/composer/packagist/issues/163#issuecommen...

  • wick

    Functional, reactive WebAssembly with a twist

  • > In Wick, we use a script to automatically update inline lint configurations for a few dozen crates.

    > https://github.com/candlecorp/wick/blob/28465f8c1492e6588bd2...

    Good lord, that is an INCREDIBLE number of lints to disable, and for... what? If you have to disable lints telling you about things like unused/dead code, intentional validation of the language's conventional style, unused/unnecessary allocations, useless/trivial type casts, ... then I really wonder what kind of code is actually being written.

  • rfcs

    RFCs for changes to Rust

  • > It also looks like (soon) you’ll finally be able to configure global lints for a project. Until now, you had to hack your solution to keep lints consistent for projects. In Wick, we use a script to automatically update inline lint configurations for a few dozen crates. It took years for the Rust community to land on a solution for this, which brings us to…

    Wow, as the author of that feature, I'm surprised to see someone was so passionate about it. I've found that many times I've been having to tell people why they should care about it.

    > I don’t know why. Maybe the pressure to maintain stable APIs, along with Rust’s granular type system, makes it difficult for library owners to iterate. It’s hard to accept a minor change if it would result in a major version bump.

    There is a tension between people wanting features and people not wanting to deal with version bumps. I've seen this a lot in maintaining clap, especially when it went from unmaintained for years to having active releases.

    As for cargo, the compatibility guarantees are tough. Take the lints table. We can't throw in a first try, knowing we can fix in in a cargo 2.0. We are tied into the rust project itself which means we have the same compatibility guarantees. This is one reason we generally encourage trying ideas out in third-party plugins before we integrate them in directly since they can break compatibility.

    > You can’t even publish a crate that has local dev dependencies

    You can; cargo automatically strips them. However, if you tell cargo that there is a version of it in the registry (by setting the version), then it must be published. This is why when I redesigned `cargo add` for being merged into cargo, I made it so `cargo add --path ../foo --dev` will not add the `version` field. We do need to find ways to clarify that the purpose of the version field is for looking it up in the registry.

    Allowing the dev dependencies to be stripped also helps with issues of circular dev-dependencies.

    > However, many developers break large projects down into smaller modules naturally, and you can’t publish a parent crate that has sub-crates that only exist within itself.

    We do have an RFC for this: https://github.com/rust-lang/rfcs/pull/3452

    The most complex part is the Index, figuring out how to represent it in the metadata tables we maintain so we avoid having to download every `.crate` file.

    I also worry there might be tech debt around assumptions of there being a single version of a package when nested packages will easily break that.

    > You can see the problem manifest in the sheer number of utility crates designed to simplify publishing workspaces. Each works with a subset of configurations, and the “one true way” of setting workspaces up still eludes me. When I publish Wick, it’s frequently an hour+ of effort combining manual, repetitive tasks with tools that only partially work.

    I'm a bit confused on this point. While there are things to improve around publishing workspaces, I'm not sure how this relates to setting workspaces up or what problems they've had with that. I'd also be curious what problems they had with releasing packages. I don't think I've seen issues from them in cargo-release's Issues.

  • Polyglot for Maven

    Support alternative markup for Apache Maven POM files

  • And you don't even need to use XML with Polyglot Maven

    https://github.com/takari/polyglot-maven

  • too-many-lists

    Learn Rust by writing Entirely Too Many linked lists

  • > Cyclic references can be dealt with runtime safety checks too - like Rc and Weak.

    Indeed. Starting out with code sprinkled with Rc, Weak, RefCell, etc is perfectly fine and performance will probably not be worse than in any other safe languages. And if you do this, Rust is pretty close to those languages in ease of use for what are otherwise complex topics in Rust.

    A good reference for different approaches is Learn Rust With Entirely Too Many Linked Lists https://rust-unofficial.github.io/too-many-lists/

  • InfluxDB

    Power Real-Time Data Analytics at Scale. Get real-time insights from all types of time series data with InfluxDB. Ingest, query, and analyze billions of data points in real-time with unbounded cardinality.

    InfluxDB logo
  • rust_cmd_lib

    Common rust command-line macros and utilities, to write shell-script like tasks in a clean, natural and rusty way

  • rust-playground

    The Rust Playground

  • https://play.rust-lang.org/?version=stable&mode=debug&editio...

    In this case, the first two errors are clear. The next 3 provide multiple, redundant context blocks. The upshot is that this simple example results in rustc printing 11 lines of useful error messages and 86 lines of useless messages. Add to that the fact that the useful error messages need not be at the top or bottom of the error list, they can be anywhere inside of it, depending on the declaration order.

  • min-sized-rust

    🦀 How to minimize Rust binary size 📦

  • Rust binaries are by default nowhere close to 500MB. If they are not small enough for you, you can try https://github.com/johnthagen/min-sized-rust. By avoiding the formatting machinery and using `panic_immediate_abort` you can get about the size of C binaries.

  • axiom

    A 64-bit kernel implemented in Nim (by khaledh)

  • I gave Rust a few chances, and always came out hating its complexity. I needed a systems programming language to develop a hobby OS[1], and Nim hit the sweet spot of being very ergonomic, optional GC, and great interop with C. I can drop down to assembly any time I want, or write a piece of C code to do something exotic, but the rest of the system is pure Nim. It's also quite fast.

    [1] https://github.com/khaledh/axiom

  • .NET Runtime

    .NET is a cross-platform runtime for cloud, mobile, desktop, and IoT apps.

  • Writing performance-sensitive code in C and calling it via interop used to be the way to go during .NET Framework days but since then has become a performance trap.

    Especially for small methods, calling them through interop is a deoptimization because they cannot be inlined, and involve GC frame transition (which you can suppress) as well as an indirect jump and maybe interop stub unless you are statically linking the dependency into your AOT deployment. In case the arguments are not blittable to C - marshalling too.

    It is also complicates the publishing process because you have to build both .NET and C parts and then package them together, considering the matrix of [win, linux, macos] x [x64, arm64], it turns into quite an unpleasant experience.

    Instead, the recommended approach is just continuing to write C# code, except with pointer and/or ref based code. This is what CoreLib itself does for the most performance-sensitive bits[0]. Naturally, it intentionally looks ugly like in Rust, but you can easily fix it with a few extension methods[1].

    [0]: https://github.com/dotnet/runtime/blob/main/src/libraries/Sy...

    [1]: https://github.com/U8String/U8String/blob/main/Sources/Share...

  • U8String

    [work-in-progress] Highly functional and performant UTF-8 string primitive for C#

  • Writing performance-sensitive code in C and calling it via interop used to be the way to go during .NET Framework days but since then has become a performance trap.

    Especially for small methods, calling them through interop is a deoptimization because they cannot be inlined, and involve GC frame transition (which you can suppress) as well as an indirect jump and maybe interop stub unless you are statically linking the dependency into your AOT deployment. In case the arguments are not blittable to C - marshalling too.

    It is also complicates the publishing process because you have to build both .NET and C parts and then package them together, considering the matrix of [win, linux, macos] x [x64, arm64], it turns into quite an unpleasant experience.

    Instead, the recommended approach is just continuing to write C# code, except with pointer and/or ref based code. This is what CoreLib itself does for the most performance-sensitive bits[0]. Naturally, it intentionally looks ugly like in Rust, but you can easily fix it with a few extension methods[1].

    [0]: https://github.com/dotnet/runtime/blob/main/src/libraries/Sy...

    [1]: https://github.com/U8String/U8String/blob/main/Sources/Share...

  • cargo-geiger

    Detects usage of unsafe Rust in a Rust crate and its dependencies.

  • Instead of looking at the crates themselves, you might want to check your (or others') Rust application with https://github.com/rust-secure-code/cargo-geiger to get a sense of effective prevalence. I also dispute that the presence of unsafe somewhere in the dependency tree is an issue in itself, but that's a different discussion that many more had in other sub-threads.

  • rust

    Empowering everyone to build reliable and efficient software.

  • That is a different problem than the one I thought you were seeing.

    We do spend a lot of time trying to silence errors that are irrelevant. We also get a lot of complaints when fixing a single error produces a wave of new errors that were hidden due to failures in earlier stages. It's a balancing act.

    Also, specific errors are verbose in order to give people a fighting chance to fix their issue. An error that is too verbose is annoying. An error that is too terse will leave users in the cold as to what the problem was. It's yet another balancing act.

    I filed https://github.com/rust-lang/rust/issues/117233 for you. Could I ask you why you didn't consider doing so when you first encountered this problem?

  • subgroup1

  • Ah that makes sense. I think Go did somewhat stumble a bit in the early days due to this, especially with repositories in GitLab, where GitLab allows essentially a directory tree where your repository can be nested indefinitely in directories like `https://gitlab.com/mygroup/subgroup1/subgroup2/repository`.

    I still don't think this is a huge issue, to be honest. Not one big enough for me to complain about, for sure. But it's definitely not ideal.

  • SaaSHub

    SaaSHub - Software Alternatives and Reviews. SaaSHub helps you find the best software and product alternatives

    SaaSHub logo
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