-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
Discriminant bits #2684
Discriminant bits #2684
Changes from all commits
8c11eb5
20eecb1
8a8974b
5c30824
7099bd2
56fb77a
7d0b9d1
6253269
95c850f
550b29d
5f808df
36144c0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,120 @@ | ||||||
- Feature Name: discriminant_bits | ||||||
- Start Date: 2019-04-01 | ||||||
- 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 | ||||||
|
||||||
Add methods to `std::mem::Discriminant` which inform of the space necessary for a bitwise representation of an enum's discriminant and the bits itself in an opaque fashion. | ||||||
|
||||||
# Motivation | ||||||
[motivation]: #motivation | ||||||
|
||||||
Rust encourages using enums to encode data with multiple variants. | ||||||
An example of this can be found in the [game of life tutorial][game-of-life-tutorial]. | ||||||
|
||||||
```rust | ||||||
enum Cell { | ||||||
Dead = 0, | ||||||
Alive = 1 | ||||||
} | ||||||
``` | ||||||
|
||||||
Using these enums in collections is wasteful, as each instance reserves at least 1 byte of space. | ||||||
Similarly, `std::mem::size_of<Discriminant<Cell>>()` is at least 1 byte. | ||||||
For that reason, the Wasm book later goes on and replaces `Vec<Cell>` by [`fixedbitset`][game-of-life-exercise], ending up with a much less intuitive implementation. | ||||||
|
||||||
If it were possible to read the exact necessary size and the bit representation the descriminant, we could have a `PackedBits<T>` that uses exactly as much space as necessary. | ||||||
|
||||||
This allows for an efficient representation of discriminant sets, which is both useful for simple enums, but also for crating an index of all discriminant values present in collection. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
# Guide-level explanation | ||||||
[guide-level-explanation]: #guide-level-explanation | ||||||
|
||||||
## Disciminant data | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
`Discriminant::bit_size` is a method to retrieve the minimal number in bits necessary to represent this discriminant. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What is the significance of the word "minimal" here? Can you elaborate? |
||||||
|
||||||
```rust | ||||||
const fn bit_size() -> usize; | ||||||
``` | ||||||
|
||||||
This number is not subject to optimisation, so e.g. `Option<&str>` reports a bitsize of `1`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While being called "enum layout optimization", it's not really an optimization, but a clear set of rules of how the discriminant is represented. What is the use-case for knowing the bitsize for enums whose variants have fields? I'm wondering if it would make more sense to have |
||||||
|
||||||
For example: | ||||||
|
||||||
```rust | ||||||
enum Cell { | ||||||
Dead = 0, | ||||||
Alive = 1, | ||||||
} | ||||||
|
||||||
enum RGB { | ||||||
Red, | ||||||
Green, | ||||||
Blue | ||||||
} | ||||||
|
||||||
Discriminant<Cell>::bit_size() == 1 | ||||||
Discriminant<Option<&str>>::bit_size() == 1 | ||||||
Discriminant<RGB>::bit_size() == 2 | ||||||
``` | ||||||
|
||||||
This information can be used to pack multiple discriminants easily for efficient storage and easy indexing. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you provide a sketch in an appendix? |
||||||
|
||||||
`Discriminant<T>` gains the methods `into_bits` and `from_bits`: | ||||||
|
||||||
```rust | ||||||
fn into_bits(&self) -> u128 | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. When I first saw this, I had to wonder what crazy kind of code would have an enum with more than There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In my mind it's not just about having There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, that was my point. I had to think for a while before I remembered that explicit discriminants can be assigned. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @eddyb had actually recommended using that size, as that would be the final width of the internal |
||||||
``` | ||||||
|
||||||
Returns a bit representation of the discriminant. | ||||||
This data can be used to construct an efficient storage or index. | ||||||
|
||||||
```rust | ||||||
fn from_bits(data: u128) -> Self | ||||||
``` | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Exposing these functions does 2 things:
The type RFC 1696, which specified the current definition and behavior of In RFC 1696, @Diggsey writes about |
||||||
|
||||||
Creates a `Discriminant` from emitted bits usable for comparison. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given that I can use this function to do |
||||||
|
||||||
# Reference-level explanation | ||||||
[reference-level-explanation]: #reference-level-explanation | ||||||
|
||||||
The feature may interact with non-exhaustive enums. | ||||||
In this case, still, the currently used discriminant size should be used. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Doesn't this allow people to couple themselves to the number of variants in an enum which was explicitly requested to be non-exhaustive (to avoid that coupling)? |
||||||
|
||||||
Adding the proposed functions probably entails adding a new compiler intrinsic `discriminant_size`. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Describe the semantics of said intrinsic. |
||||||
|
||||||
Empty enums are of size 0. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. How about enums with a single variant? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Obviously size zero. As I see it, empty enums are specified in the proposal simply as an acknowledgement that they were taken into account. From a mathematical standpoint, they take |
||||||
|
||||||
# Drawbacks | ||||||
[drawbacks]: #drawbacks | ||||||
|
||||||
The added methods increase API surface in stdlib. | ||||||
|
||||||
# Rationale and alternatives | ||||||
[rationale-and-alternatives]: #rationale-and-alternatives | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section feels really anemic and contains bits copied over from the template. For a proper review, the section should be substantially elaborated upon and the questions raised in the template should be answered. |
||||||
|
||||||
- Why is this design the best in the space of possible designs? | ||||||
- What other designs have been considered and what is the rationale for not choosing them? | ||||||
- What is the impact of not doing this? | ||||||
- `from_data` and `into_data` could instead be straight `From/Into` implementations | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. And why isn't it? As aforementioned there may be specific guarantees and non-guarantees we want to make which makes |
||||||
- Alternatively, `from/into_bits` could return a `Bits<T>` type with a richer interface | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What would that richer interface be like? |
||||||
|
||||||
# Prior art | ||||||
[prior-art]: #prior-art | ||||||
|
||||||
# Unresolved questions | ||||||
[unresolved-questions]: #unresolved-questions | ||||||
|
||||||
- Naming of the functions could be improved. | ||||||
- A basic implementation of a bitfield should be created during the implementation phase | ||||||
|
||||||
# Future possibilities | ||||||
[future-possibilities]: #future-possibilities | ||||||
|
||||||
The feature is self-contained and I don't see direct extensions. | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
|
||||||
[game-of-life-tutorial]: https://rustwasm.github.io/docs/book/game-of-life/implementing.html | ||||||
[game-of-life-exercise]: https://rustwasm.github.io/docs/book/game-of-life/implementing.html#exercises |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.