I have no idea whether this is a good idea, but it just popped into my head, especially w.r.t. Termination
being stable.
We add a new trait (all names are silly placeholders):
pub trait Implicit {
fn from_nothing_something() -> Self;
}
impl Implicit for () {
fn from_nothing_something() {}
}
impl<E> Implicit for Result<(), E> {
fn from_nothing_something() { Ok(()) }
}
Whenever a block ends with the empty expression (i.e. an implicit ()
value is added as the block result), the block instead returns Implicit::from_nothing_something()
, with a unbound type fallback to ()
[1].
This would mean that you could write something like
fn main() -> eyre::Exit {
jane_eyre::init()?;
init_tracing()?;
do_main()?;
thank_you_for_playing_wing_commander()?;
}
and then behavior of program termination would be determined by eyre::Exit::report(AppError.into())
in the failure case, and eyre::Exit::report(from_nothing_something())
in the
success case.
Notably,
fn do_stuff() {}
fn main() -> eyre::Exit {
do_stuff //~ ERROR: mismatched types
}
Implicit
would only be used in the case where a block ends with a statement and not an expression.
(... and in the case of if {} else {}
which is conditionally an expression or a statement based on tyck ... )
-
This fallback behavior is the same as is used by
{integer}
and{float}
literals. This fallback is not available to be used for anything other than these two pseudotypes, so this necessarily makes this feature a far-future kind of thing blocked on making type fallback more available; e.g. work on custom literals also requires this. ā©ļø