- Feature Name:
inferred_variants
- Start Date: 2022-09-14
- RFC PR: rust-lang/rfcs#0000
- Rust Issue: rust-lang/rust#0000
Summary
Introduce optional language-level feature that allows writting SomeVariant
versus SomeEnum::SomeVariant
where SomeEnum
is expected. For this, one must configure the package Cargo.toml
with the following:
[language-features]
inferred-variants = true
As outlined later in this document, starting from a specific Rust edition, depending on community decisions, this feature could be enabled by default.
While some say enabling this may break existing code, the chance to break is mostly impossible, as covered in the section Reference-level explanation. Regardless, it is an optional feature.
Another thing to add is, Cargo's cargo init
or cargo new
commands may automatically generate this option as true
.
Motivation
This aims at reducing enum
qualifier verbosity in any context. This allows to omit workarounds such as use SomeEnum::*;
and use SomeEnum as Se;
;
Guide-level explanation
According to the configuration of the current package, where language-features.inferred-variants = true
:
- Given a lexical reference with an expected
enum
typeE
: if it matches the name of any of the variants fromE
, it results in such variant; otherwise the default reference resolution takes place for the lexical reference.
Reference-level explanation
A reference to an enum
variant can be written in different ways depending on the context:
enum SomeEnum {
SomeVariant,
}
fn some_fn(et: SomeEnum) {
}
some_fn(SomeEnum::SomeVariant); // full
some_fn(SomeVariant); // inferred
With this language feature, a lexical reference may incorrectly refer to an enum
variant where the user may desire to refer to any item else with the same name, but this only happens where an enum
is expected. This can be referred to as shadowing.
While shadowing problems are hard to occur, since they only happen where a specific enum
is expected, the workaround to refer to something shadowed by an inferred enum
variant is to use an use ...;
statement. For example:
enum E { Bar, }
use xns::Bar as TBar;
To re-enforce: unwanted lexical shadowing is almost impossible to occur, because the inference only takes place where the enum
is expected. Thus, one more example that illustrates how that is almost impossible to happen:
struct S;
enum E { S, }
let v: S = S;
let v: E = S;
More examples: the expression Foo::x()
never necessarily resolves to a variant Foo
, because this is a member expression and Foo
is the base object and x
is the member. Such expression can be resolved expecting some enum
, however it is a member expression.
To re-enforce (2): aware of the lexical mechanism, enabling this feature on an existing project/package is almost impossible to break the code, even if a lexical item has the same name as an expectable variant.
Drawbacks
N/A
Rationale and alternatives
- Ideas such as
_::SomeVariant
seem to be noisy:
// MyOwnResult
some_fn(Ok(v));
some_fn(_::Ok(v));
match r {
Ok(v) => ...,
Err(reason) => ...,
}
match r {
_::Ok(v) => ...,
_::Err(reason) => ...,
}
- Not having this feature is a lack of opportunity for future adoption. For example, starting from an edition year, this can become a feature enabled by default.
Prior art
- Other languages have the feature in different forms:
- Haxe:
var sv:SomeEnum = SomeVariant;
- Swift:
let sv: SomeEnum = .SomeVariant;
- Haxe:
- Some users may expect this to be
true
by default, at least starting from a particular Rust edition. - The feature is simple to implement.
Unresolved questions
N/A
Future possibilities
N/A