Swift, too, has only Never and no magic type, only recognition of a caseless enum as uninhabited. But you didn’t suggest getting rid of ! or making it an alias of std::convert::Infallible, both of which have been proposed in the past (with unfortunate complications that make it easier said than done); you suggested having both.
It is like to say, why are you not create own MyOption<T>, MyResult<T,E> or MyUnit?
Nothing forbids to use own MyNever, except of optimization: all code which deals with pure !never type is always "unused" and could be removed. It exists for type-checking only.
P.S. "!any" is not "unused", and now the compiler guess of optimization and about the role.
!anyis unused. That’s why you get unreachable code warnings from code after a panic. The compiler will remove such code today, and it’s correct to do so.
Interesting, this example was added, before I add a remark :
in Generics it could be used, but as a "result" type only, ... -> T
in Arguments type it could be used, but as a "result" type only, ... -> !any
Now this example it totally Ok for T=!any (except function any_in_args())
pub trait Ret {
type Ty;
}
impl<T> Ret for fn() -> T {
type Ty = T;
}
pub type Any = <fn() -> !any as Ret>::Ty;
pub fn any_in_args2(_: !never) -> Any {
panic!()
}
// this is must not compile - Argument cannot have type !any
pub fn any_in_args(_: Any) -> Any {
panic!()
}
You are probably thinking of Haskell lazy semantics. Rust is a strict language and there is no concept of a value that has started but hasn't finished calculating. A function is what calculates, not a value of some type. Once you create a value of a type, it has already "finished" being created.
So this distinction is meaningless.
! is also an uninhabited type. If what you mean is that it's impossible to write a Haskell expression that has type Void then it's just false -- here is one:
In type theory, the bottom type is a subtype of every other type. In other words, bottom is what you call "any".
In Rust it's a bit different because ! isn't technically a subtype of other types, rather it implicitly coerces to other types, but it's the same idea.
Sure, we could have <T> ... -> T instead of !any, but this breaks backward compatibility, because we must change all expression, which already use !any into:
In rust we do not care if "bottom"! is a part of "any"! or not (spoiler: it is, but we do not care)
And NO, what I call "any" is not a real bottom type, because panic!() is not an "infinite calculations", but halting a program. This only true for empty loop {}.
The bottom type does not necessarily mean "infinite calculation". A type doesn't describe a calculation at all, types represent sets of values. The bottom type is the empty set of values.
It makes sense for a function that never returns to return bottom.