[Pre-RFC] introduce struct groups (modified enums)


#1

Summary

The idea is to add struct groups. Similar to enums in structure. You have a group name and then variants under it. Each “variant” would be a reference to a struct that has been defined. You could then use this group as a type for arguments in functions and as a return type. But you could also address individual structs normally. When the group name is used for a type, it acts like an enum and you would need match to get which variant it is.

Motivation

This is useful in cases where you want to accept any struct from a range of structs, but then you also want to be able to return individual variants of the group from some functions without having to return the entire enum and leave the end use having to do a match case just to get the result.

Detailed design

The structure would very much be like an enum. So I’ll start with the syntax.

struct Item1 {
    ...
}

struct Item2 {
    ...
}

group Items {
    Item1,
    Item2,
}

fn purchase(item: Items) {
    match search_items("foo") {
        Item1 => { ... },
        Item2 => { ... },
    }
    // To show you can accept it as an argument
}

fn search_items(s: &str) -> Option<Items> {
    // Showing that you would be able to return `Items`

    // The code running this would be similar to when you return an enum
    // match search_items("foo") {
    //     Item1 => { ... },
    //     Item2 => { ... },
    // }
}

fn item2_to_item1(item: Item2) -> Item1 {
    // This is to show that you can still use the structs as normal
}

As shown in the examples, it would work just as an enum except that the pieces are previously made structs which you can still use on their own. Not much I think I could explain really. Sorry if I’m not providing enough detail.

How We Teach This

This is a fairly simple concept and can be taught right along with enums since it relates mostly to it. A small section about groups and their uses would be needed. For terminology I’m not sure what to call the structs in the group. Something like members or items. Variants doesn’t seem appropriate.

Drawbacks

It seems slightly redundant as its super close to Enums

Alternatives

Using an enum with unit variants for everything that just point to a struct. (Which is not that elegant) You could also use traits but you cant have your return type as “a struct that implements X” iirc.

Unresolved questions

Besides what to call the structs in the group, not any that I have, but I’m sure I might have missed something, which is why I’m coming here for feedback.


#2

In fact its possible to just make enums behave this way. There was an RFC under consideration to do that, which has been postponed:

https://github.com/rust-lang/rfcs/pull/1450


#3

I would like to think mine is at least slightly different, but i see that it mostly isn’t and I’m just going to have to wait a long time to get unions. Thanks for the link, it seems i hadn’t searched this thoroughly enough


#4

I’d emphasize the parts of this that are different, like how it allows mixing the same structs into different enums. If you have motivation for having both enum ItemsA { struct Item1, struct Item2 } and enum ItemsB { struct Item2, struct Item3 }, then that’d be good information to have when things come up again.

Also, what are the syntax and/or inference rules for going from an Item2 to an ItemsA or ItemsB?


#5

You could use the group mixing in order to create an index. If the program was meant to catalog shirts. You could have a lot of shirt structs and group them into what color they are or size.

I was thinking something like if Struct1 in Group1 && Struct1 in Group2 but that would require the ability to use a struct name as an reference to the struct which I think I’ve seen an RFC for.

For inference rules, I initially thought about how type works to make an alias. But then I thought what if the struct you were referring to in ItemsA was not in ItemsB, and that can’t be checked at compile time due to a function being able to return ItemsA so you don’t know which one it returned. A result to unwrap or just using a match case and then repackaging it into ItemsB. Which I think the as keyword would make sense here.