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

Reply via email to