I was reading a proposal about adding "datasort refinements" to make enum
variants first-class types, and it seems to me there is a simpler and more
effective way of solving the problem.
The idea is that if A, B and C are types, then "A | B | C" is a "structural"
enum type that can be either A, B or C.
In addition, A can be implicitly converted to "A | B", "A | B" can be
implicitly converted to "A | B | C", and also "(A | B) | C" and "A | (B | C)"
are equivalent to "A | B | C", and finally "C | B | A" is equivalent to "A | B
| C" (to support the latter, the implementation needs to sort variants in some
arbitrary total order before assigning tag numbers).
Furthermore, a way to bind variables to an "or" pattern is introduced to allow
to convert "A | B | C" to "A | B" in the case that it holds an A or a B.
This way, one can rewrite Option as a type alias like this:
struct Some<T>(T);
struct None;
type Option<T> = None | Some<T>;
Which is like the current Option, but also makes None and Some<T> first-class
types.
The current enum syntax can remain as syntax sugar for the above code.
The only issue I see is what to do for code such as "let mut x = Some(3); x =
None;": with this proposal, Some and None are separate unrelated types, so we
either have this code emit an error, or x must be given the type "Some<int> |
None" automatically, which however can lead to obscure error messages if one
mistakenly attempts to assign a string to it causing the type to become
"Some<int> | None | ~str" (i.e. the user might be told than a match is not
exhaustive because it does not handle the "~str" case, rather than that they
assigned a ~str to an Option-typed variable).
It should be possible to allow this, and make the error-emitting code use
heuristics to figure out whether it is more likely that the user assigned a
value of the wrong type, or used an enum improperly (for example, by looking at
whether the implicitly created enum type is ever written explicitly in the
source, and whether the deduced structural enum type is being used in places
that require a non-enum type).
Alternatively, one can stipulate that only types that are structs, or that are
structs marked "enum struct" or "case struct" or similar can become part of an
inferred structural enum, but this seems unappealing.
Note that some structural enums can change representations depending generic
instantiation, since "T | int" becomes just "int" if T = int, while it is "~str
| int" if T = ~str (and similar for "Some<T> | Some<int>"), but this should not
be a problem.
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev