Rust enums and generalization

In my understanding, an enum variant is actually is a value constructor for the enum type.

enum Enum {
    A(u8),
    B { x: f32, y: f32 },
}

In above definition, the variants have the form, A(u8) -> Enum B { x: f32, y: f32 } -> Enum

Is there way to generalize this behavior for other constructors? For e.g.,

struct S {
    x: f32,
    y: f32,
}

Here any value construction of type S will always return type S. But is it possible for us to simulate the idea that a value constructor using S will return a different type T? Something like a GADT. I believe it is not directly possible, but are there language constructs that would make it possible for us to implement this behavior? I am not that expeienced in Rust language. So apologies if this does not make a lot of sense.

Can you say more about your use case? What sort of input expression would you want to produce what type?

In general, if you want a "type-level function" where the output's type is picked in some way other than it having been explicitly written, you will need to involve a trait. But I am not sure what you want to achieve in this case.

(Note that enum variants themselves are not types at all.)

Apologies, if my question was unclear.

You actually pointed out the issue that I am trying address, i.e., enum variants are not types. I am trying to create each variant to be a separate type.

If we take an enum with two variants, say A & B as in the following:

enum E {
    A,
    B(u8),
}

let a = E::A;
let b = E::B(10);

Here a and b are both of the same type E. Effectively I have two different states, but common interface and implementations.

If I wanted to make A and B into separate types (say because I am trying to create type states or similar implementation), then I will do something like this.

struct A;

struct B(u8);

trait E {}

impl E for A {}
impl E for B {}

This is fine if I am willing to pass around trait in my interfaces. But I am trying to pass around concrete type E as in the enum case without having to deal with dynamic dispatch, object safety issues etc.

Roughly what I want to be able to do is the following: When in State A -> It Returns type E and behaves like E When in State B -> It Returns type E and behaves like E.

Not sure if this makes any more sense.

Thanks for your help.

Many people would like Rust to have enum variant types, but it hasn't happened yet because it would mean introducing (additional) subtyping to the Rust type system, and it's very hard to combine subtyping and type inference.

What you can do today is use separate structs and an enum:

struct A;
struct B(u8);

enum E {
    A(A),
    B(B),
}

impl From<A> for E {
    fn from(a: A) -> E { E::A(a) }
}
impl From<B> for E {
    fn from(b: B) -> E { E::B(b) }
}

This gets you the ability to have types A and B, combine them into type E, and match them to go back to narrower types.

You might also write a trait that is implemented for all of the involved types in order to enable generic code to accept any of E, A, B:

trait Eish {
    // ... common operations go here ...
}
impl Eish for E {...}
impl Eish for A {...}
impl Eish for B {...}

Then you have both the enum and the trait available, and can use whichever one fits the specific situation better.

1 Like

Thank you very much for the answers. I have a slightly different take on the subtyping issue. Let me try to write it up and then bring it here.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.