This is incorrect. The compiler has always treated `Infallible` as uninhabited, and used that fact for optimizations. The downside of its lack of compiler support is losing out on the coercions. (The article is excellent otherwise)
Stabilizing Rust's Never Type (lwn.net)
Georgelemental 3 hours ago
cipherjim 4 hours ago
Return Result<T, !> and the compiler knows that callers never have to check the error case because by definition it can’t be constructed.
xg15 6 hours ago
If ! can coerce to every type, why not treat it as if it implemented every trait too?
tux3 6 hours ago
So this would risk turning a compile-time error into a runtime error.
dlubarov 6 hours ago
SkiFire13 4 hours ago
10000truths 4 hours ago
Another ! makes sense to me here. Are there any cases where it doesn't work to auto-assign ! to all associated types of a ! trait impl? Associated constants might require some mechanism similar to `compile_error!()`.
xg15 6 hours ago
Sharlin 5 hours ago
LatticeAnimal 5 hours ago
kibwen 5 hours ago
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).
amomchilov 4 hours ago
I just checked, my main side project only has less than 10 things that return never. `-> Never` reads even better, imo.
kibwen 4 hours ago
And if you'd like to write `-> Never`, the nice thing about being a first-class type is that you can now just do that if you'd like, via a standard type alias: `type Never = !;`.
p1necone 3 hours ago
sheept 3 hours ago
[0]: Example: std::process::exit returns `!` https://doc.rust-lang.org/1.0.0/std/process/fn.exit.html
Georgelemental 3 hours ago
(There is a trick you can abuse to access the type everywhere: https://docs.rs/never-say-never/latest/never_say_never/)
salsa_catsup an hour ago
weinzierl 6 hours ago
"When is never?"
kccqzy 5 hours ago
jadenPete 5 hours ago
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.
kccqzy 4 hours ago
Rust is not a subtyping based language, except for traits and lifetimes. So statements like never being at the bottom of the type hierarchy is irrelevant here even though it is correct. If Rust had higher rank types the never type is also (forall a. a) but still it doesn’t matter. It is simply surprising for a type to be converted implicitly according to subtyping rules other than for traits and lifetimes.
SabrinaJewson 2 hours ago
kccqzy 2 hours ago
kibwen 2 hours ago
fn unwrap<T>(t: Option<T>) -> T {
match t {
Some(foo) => foo,
None => panic!()
}
}
...and this function couldn't otherwise typecheck because it doesn't return a `T` in the `None` branch. You need coercion here.kccqzy 2 hours ago
Generally languages with such polymorphism have a never type only because they don’t also support impredicative polymorphism.
kibwen 8 minutes ago
SabrinaJewson 2 hours ago
From a more category-theoretic perspective, a type A is a “subtype” of a type B when there is an embedding of A inside B. In this sense, `!` is a subtype of every type (which is its universal property). But this definition also grants you that `String` is a subtype of `BigInt`, because strings can be coded as bit sequences which can be coded in `BigInt`, which may or may not be what you expect.
From a programming languages perspective – and this is the terminology generally used in Rust – a type A is a “subtype” of a type B when `a: A` implies that `a: B`. In this sense, `!` is only a subtype of itself; although it coerces to any other type, it’s not _literally_ of that type, the coercion is just invisible in syntax. Importantly, if A is a subtype of B then `Vec<A>` is a subtype of `Vec<B>` – but `Vec<!>` is definitely not a subtype of `Vec<T>`, since they may have totally different layouts in memory (the former not allocating at all, while the latter potentially allocating).
kccqzy 2 hours ago
That’s just not true. Java would permit it but then you get ArrayStoreException so this is unsound from a type system perspective. To make this sound, we need to classify each use of a type parameter to be covariant, contravariant, or invariant.
echelon 4 hours ago
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, rustonly, nolinking, etc. flags.
kibwen 4 hours ago
cipherjim 3 hours ago
It cannot by definition happen at runtime because the never type has no values and thus cannot be constructed under any circumstances.
Any compile time coercions that occur would convert types (or generics args of types) to !
I find it difficult to imagine any situation where that would result in a working program - only if the coerced types or references to coerced generics were not even used would it compile.
munchler 6 hours ago
SabrinaJewson 2 hours ago
kibwen 20 minutes ago
epolanski 6 hours ago
A simple TypeScript example:
const forever = (): never => { while (true) { // whatever } }
HNBeLike 2 hours ago
Nobody should get ahold of this technology.
Shut down the schools!
Get rid of all small business (to mitigate the risk).
15 days to prevent Never from destabilizing!
We’re all in this together.