Enum sub typing?


#1

I’m learning Rust slowly because of my job hours, but eventually I’ll know enough to start contributing.

In some of my Rust code I’ve seen that sometimes I’d like to specify only a subset of the enum variants. Using a hypothetical syntax:

enum Foo { A, B, C }

fn bar(x: Foo::A) -> Foo::{A, C} { … }

This code means that both the input and output of the function bar() are a Foo enum, but the input is allowed to be only an Foo::A, and the output a Foo::A or Foo::C. The compiler verifies statically that the code is correct, so the enum tags aren’t read at run-time. If the compiler can’t assert the correctness of the code statically, the code doesn’t compile (verifying the tags at run-time where it can’t be done statically is an alternative design, but it’s just a way to shorten the code you write now, so I think it’s not a good idea).

There’s also a simple sub-typing:

type FooA = Foo::A;
type FooAB = Foo::{A, C};

let mut a: FooA = Foo::A;
let mut b: FooAC = Foo::C;

b = a; // OK, a is a subset of b.
a = b; // Compile-time error.

Is this a reasonable feature to ask for Rust? And is this of sufficient common usefulness?


#2

Datasort refinements have been a proposed/considered feature for at least 4 years. However, there clearly hasn’t been any movement on it for a long time.

There’s several tricky aspects, such as, if we introduce the subtyping, making sure things are backwards compatible. E.g. vec![None; 10] probably wants to be a Vec<Option<T>>, not a Vec<Option<T>::None>. The latter wouldn’t be able to have Somes pushed onto it. I’m led to believe that subtyping like this makes type inference very difficult.

If you have subsets of variants that are commonly used by themselves, you can often break them out into separate enums, e.g. enum Foo { X(Bar), B } enum Bar { A, C }.

(The enum-based approaches for virtual structs are relevant too.)