Stabilizing Rust's Never Type

(lwn.net)

104 points | by cjd8 3 days ago

6 comments

  • xg15 1 hour ago
    > After this change (and on the 2024 edition), the compiler assumes that T should be !, which doesn't implement Default, and therefore causes a compilation error.

    If ! can coerce to every type, why not treat it as if it implemented every trait too?

    • tux3 1 hour ago
      The Default trait provides a function that actually constructs the type in question. But here the ! type can never be constructed, so the only way to implement Default would be to have it panic, loop infinitely, or otherwise fail at runtime.

      So this would risk turning a compile-time error into a runtime error.

      • dlubarov 1 hour ago
        Moreover, Rust traits' associated constants/types get in the way of having a proper bottom type. What would <! as Iterator>::Item be? (In Scala I think it just doesn't compile?)
      • xg15 1 hour ago
        Ah, that makes sense. Rust noob here, so I wasn't aware traits can act on types directly without any instance of the type. Thanks for the info!
        • Sharlin 1 hour ago
          Yep, they can have static methods, as it were (in Rust lingo called "associated functions"; "methods" in Rust always take a `self` receiver). Traits can also have associated types and associated constants, which (naturally) also relate to the type, not any particular instance.
  • kccqzy 39 minutes ago
    The lesson here is that implicit conversions are bad. The never type itself having implicit conversions to other types is bad enough (even though such coercions are logically valid: “ex falso quodlibet” they should be explicit), but having a fallback type when type inference doesn’t have enough information to produce a type is even worse. Rust is famous for not even having implicit numeric coercions (say from i8 to i32) but it seems like a shortsighted decision to allow implicit coercions here.
    • jadenPete 25 minutes ago
      Why is it bad? Implicit integer conversions are generally bad because they can produce unexpected behavior at runtime and obstruct what’s really happening, but that doesn’t seem to be what’s happening here.

      Never is a standard type in many languages and is at the bottom of the type hierarchy because it’s a subtype of every type. Never isn’t implicitly converted any more than `&’a A` is “implicitly converted” into a `&’b B`, where `’a` subsumes `’b`. There’s no runtime conversion because there will never be an instance of never—it represents the value of a computation that never completes by definition.

      I think what you mean to say is that implicit runtime conversions are bad, not that all subtyping is bad.

    • echelon 2 minutes ago
      We should be able to set at a crate level whether our code can compile with panics, implicit conversions, etc. And we should be able to blacklist dependencies and transitive dependencies that do these things. We should be able to advertise a crate's safety and attention to detail.

      Higher level application code can benefit from this, but core libraries should forbid this statically and be prevented from even compiling or being imported should these things be enabled.

      We should be able to filter crates.io by these properties, and force our own projects to abide by them.

      I want nopanic, nocoerscion, maxdependencydepth, etc.

  • weinzierl 1 hour ago
    Relevant talk by Waffle at RustWeek earlier this year:

    "When is never?"

    https://youtube.com/watch?v=3jM4cnEVrLc

  • LatticeAnimal 1 hour ago
    Is it obvious to rust developers that "!" would be the never type? I frequently use "never" in typescript. I could imagine using the never type frequently in rust too. I feel like a longer more human-understandable name would've been a good decision here. (feels like more rust jargon that makes the language harder to learn)
    • amomchilov 1 minute ago
      Yeah it really baffles me why a symbol like `!` was spent on this, which could be more useful for more a more commonly used feature.

      I just checked, my main side project only has less than 10 things that return never. `-> Never` reads even better, imo.

    • kibwen 54 minutes ago
      > Is it obvious to rust developers that "!" would be the never type?

      Prior to this change most Rust developers would never have cause to ever use `!` for any reason. The only stable way to do so would be to specify the quote-unquote "return type" of divergent functions, which Rust has supported via this special-cased syntax since prehistoric days, before even Mozilla got involved. You can see it in the oldest capture of the tutorial from Jan 2012: https://web.archive.org/web/20120109041112/http://www.rust-l...

      So when it came time to elevate `!` from being a special-cased return type to being a fully-fledged type, it was only natural to reuse this syntax. However, I tend to agree that, because we call it "the never type" in casual conversation, the most natural thing to do would be to just have a type alias called `Never` that we could encourage people to use instead. But that would be a perfectly backwards-compatible change that could be made at any point (as proven by the fact that the stopgap and long-stable `Infallible` type is becoming just such a type).

  • munchler 1 hour ago
    As a fan of the Curry-Howard correspondence, I approve of this decision.
  • epolanski 1 hour ago
    The never type seems very useful in various languages to either signal that a branch can never happen (the example of string -> bytestring never erroring) or to mark that a function will never return a value (and thus control) to the caller.

    A simple TypeScript example:

    const forever = (): never => { while (true) { // whatever } }