-
Notifications
You must be signed in to change notification settings - Fork 1.6k
Inferred types _::Enum
#3444
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
JoshuaBrest
wants to merge
14
commits into
rust-lang:master
Choose a base branch
from
JoshuaBrest:master
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+233
−0
Open
Inferred types _::Enum
#3444
Changes from 3 commits
Commits
Show all changes
14 commits
Select commit
Hold shift + click to select a range
10584e3
Infered enums
JoshuaBrest cc80833
Change file name
JoshuaBrest bbfe249
Make it better
JoshuaBrest fb47866
add additional point.
JoshuaBrest 1e56cef
Fix typo
JoshuaBrest 7934f4e
Improve clarity by @teror2345
JoshuaBrest 060b421
Correction by @teor2345
JoshuaBrest aab1794
Apply suggestions from code review by: @SOF3
JoshuaBrest d5bb4eb
Grammer and file name change
JoshuaBrest b1b3b2f
`_::method()` is not allowed
JoshuaBrest 6311c49
Spelling correction
JoshuaBrest 55f8066
Rewrite and fully outline (in more detail) how this feature will work
JoshuaBrest 0338f94
Remove formating changes done by Microsoft Word.
JoshuaBrest 8d44a91
Add examples and remove detail on compiler errors in Reference-level …
JoshuaBrest File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
- Feature Name: Inferred Types | ||
- Start Date: 2023-06-06 | ||
- RFC PR: [rust-lang/rfcs#0000](https://github.com/rust-lang/rfcs/pull/0000) | ||
- Rust Issue: [rust-lang/rust#0000](https://github.com/rust-lang/rust/issues/0000) | ||
|
||
|
||
# Summary | ||
[summary]: #summary | ||
|
||
This RFC introduces a feature allowing the base type of enums and structs to be inferred in contexts where strict typing information can be exist. Some examples of strict typing include match statements and function calls. The syntax is `_::EnumVariant` for enums, `_ { a: 1 }` for constructing structs, and `_::method()` for impls and traits wher `_` is the type. | ||
|
||
|
||
# Motivation | ||
[motivation]: #motivation | ||
|
||
Rust's goals include clean syntax, that comes with a consice syntax and features like macros making it easier to not repeat yourself. Having to write a type every time you want to do something can be very annoying, repetetive, and not to mention messy. This is a huge problem especialy in large projects with heavy dependency on enums. Additionaly, with large libraries developers can expect to import upwords from 3 traits, structures, and enums. One way developers have solved this is by importing everything from specific modules like [`windows-rs`](https://github.com/microsoft/windows-rs). This is problematic because at a glance, it can not be determined where a module comes from. It can be said that developers need a low compromise solution to solve the problem of large imports and messy code. The intent of this RFC’s is to create something that developer friendly yet still conforming to all of rust's goals. | ||
|
||
# Guide-level explanation | ||
[guide-level-explanation]: #guide-level-explanation | ||
|
||
When crating a struct or enum, infered types can simplify the type into just a underscore. It is important to note, however, that they do not work when the type is not specific enough to be infered like: type parameters. Below are some examples where they do and don't work. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Function calls (structs): | ||
```rust | ||
fn my_function(data: MyStruct) { /* ... */ } | ||
|
||
// my_function(MyStruct { | ||
// value: 1 | ||
// }); | ||
my_function(_ { | ||
value: 1 | ||
}); | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
|
||
Function calls (impl): | ||
```rust | ||
fn my_function(data: MyStruct) { /* ... */ } | ||
|
||
// my_function(MyStruct::new()}); | ||
my_function(_::new()); | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Function returns (enum): | ||
```rust | ||
fn my_function() -> MyEnum { | ||
// MyEnum::MyVarient | ||
_::MyVarient | ||
} | ||
``` | ||
|
||
Match arms: | ||
```rust | ||
enum Example { | ||
One, | ||
Two | ||
} | ||
|
||
fn my_fn(my_enum: Example) -> String { | ||
match my_enum { | ||
_::One => "One!", | ||
_::Two => "Two!" | ||
} | ||
} | ||
``` | ||
|
||
It is important to note that `_` only represents the type; if you have (for example) another enum that can be coerced into the type, you will need to specify it manually. Additionally, any traits required to call an impl will still have to be imported. | ||
|
||
```rust | ||
fn my_function(data: MyStruct) { /* ... */ } | ||
|
||
|
||
my_function(MyStruct2::do_something().into()); // ✅ | ||
|
||
|
||
my_function(_::do_something().into()); // ❌ error[E0599]: variant or associated item not found in `MyStruct` | ||
``` | ||
|
||
|
||
# Reference-level explanation | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
[reference-level-explanation]: #reference-level-explanation | ||
|
||
The underscore operator infers the type of a stuct or enum where there is enough type information in a context in order to infer an exact type. In a statement like `_::Variant`, you can imagine the underscore to be the type. That means that anything you could do with an actual type like `MyEnum::Variant` will still apply in an infered enum. Ultimately, the enum or struct doesn't need to be imported but, traits and other specfied things will need to be imported. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Due to how the rust compiler currently works, lots of changes will need to be made to allow paths to be infered in an order that allows for all of the mentioned. One issue is getting the type of a given context mentioned in [rust-lang/rust#8995](https://github.com/rust-lang/rust/issues/8995). | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Finally, here are some examples of non-strict typings that can not be allowed. | ||
```rust | ||
fn convert<T>(argument: T) -> Example {/* ... */} | ||
|
||
do_something(convert(_::new())) | ||
// ^^^^^^^^ Cannot infer type on generic type argument | ||
``` | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
However, ones where a generic argument can collapse into strict typing can be allowed. The below works because `T` becomes `Example`. This wouldn’t work if `do_something`, however, took a generic. | ||
```rust | ||
fn do_something(argument: Example) {/* ... */} | ||
fn convert<T>(argument: T) -> T {/* ... */} | ||
|
||
do_something(convert(_::new())) | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
``` | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
# Drawbacks | ||
[drawbacks]: #drawbacks | ||
|
||
In the thread [[IDEA] Implied enum types](https://internals.rust-lang.org/t/idea-implied-enum-types/18349), many people had a few concerns about this feature. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
These RFCs could create bugs. An example of this is if a function changes has two enum parameters that share common variant names. Because it’s implied, it would still compile with this bug createing unintended behavior wharas by specifying the type names, the compiler would thrown an error. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
```rust | ||
enum RadioState { | ||
Disabled, | ||
Enabled, | ||
} | ||
|
||
enum WifiConfig { | ||
Disabled, | ||
Reverse, | ||
Enabled, | ||
} | ||
|
||
fn configure_wireless(radio: RadioState, wifi: WifiConfig) { /* ... */ } | ||
``` | ||
|
||
Another issue with this is that the syntax `_::` could be mistaken for `::` meaning crate. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
# Rationale and alternatives | ||
[rationale-and-alternatives]: #rationale-and-alternatives | ||
|
||
There have been many ideas for what this operator should be including `::` add `.`. Despite that, the underscore is the best because it has already been used to infer lifetimes. Additionally the underscore by itself can be used to construct a struct creating a consistent experience. Maintainers should accept this proposal because it can simplify writing Rust code and prevent the large problem of reputition in switch statements. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
|
||
# Prior art | ||
[prior-art]: #prior-art | ||
|
||
|
||
Apple’s Swift had enum inference since 2014 and is not used in most swift codebases with no issues. One thing people have noticed, though, is that it could be used for so much more! That was quite limited and in creating a rust implementation, people need to extend what swift pioneered and make it more universal. That is why this RFC proposes to make the underscore a general operator that can be used outside the small use case of enums and allow it to be used in structs. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Unresolved questions | ||
[unresolved-questions]: #unresolved-questions | ||
|
||
|
||
The implementation of this feature still requires a deep dive into how exactly the compiler should resolve the typings to produce the expected behavior, however, algorithems for finding paths for do an already exist. | ||
JoshuaBrest marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
# Future possibilities | ||
[future-possibilities]: #future-possibilities | ||
|
||
|
||
I can’t think of anything |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.