-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Description
- Start Date: (fill me in with today's date, YYYY-MM-DD)
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)
Summary
Add an Empty type to libcore. Use it to replace the fn() -> ! sytax.
Motivation
See some previous discussion here: http://internals.rust-lang.org/t/should-be-a-type/1723 here: rust-lang/rust#20172 and here: rust-lang/rust#18414
Edit: @reem has already implemented a crate for this. See: https://github.com/reem/rust-void
A standard Empty type (ie. an enum with no variants) would be a useful addition to the standard library. One use case is if you need to implement a trait method that returns Result<_, Err> where Err is an associated type but you know that your implementation cannot fail. Currently, library authors can easily define their own empty types, but this will result in multiple libraries defining the same thing.
Making diverging functions ordinary functions also allows them to be used in generic code. For example, it would allow functions that diverge to be passed as arguments to higher-order functions.
Removing ! and replacing it with a plain ol' type will make Rust slightly simpler.
Detailed design
Add this to libcore:
[lang="empty"]
enum Empty {}
impl Empty {
fn elim<T>(self) -> T {
match self {}
}
}
Add an empty lang item so that intrinsics like abort can return it. Make all methods that are currently marked as diverging (eg. panic, abort) return Empty instead. Make the panic! macro expand to begin_unwind(...).elim() instead of just begin_unwind(...) to avoid users having to add the .elim() themselves.
Add a convenience method to Result<T, Empty>:
impl<T> Result<T, Empty> {
fn to_inner(self) -> T {
match self {
Ok(x) => x,
Err(e) => e.elim(),
}
}
}
Drawbacks
This change will require typing .elim() where previously someone wouldn't have had to. But only when calling a diverging function from a non-diverging function without using one of the panic! family macros. In the future, Rust's type checker could be improved to allow any type which is isomorphic to Empty to unify with any other type.
It might make things like reachability checking more difficult. But it would be nice anyway if the compiler could detect unreachable code after code that produces an empty value.
! used to be treated as a type though, but this was removed due to maintenance difficulties.
Alternatives
Just add an Empty type to libcore but keep the seperate divergence syntax aswell.
Name it Never as in "this value can never exist" or "this function can never return". Name it Void. However this is likely to confuse programmers from a C-family language background as Void is not (). Name it Bottom. Name it something else.
Unresolved questions
Is there time to make this change before 1.0?