[Pre-RFC] Templating over enums


#1

Templates are awesome, and being able to have where clauses for traits on them make them really useful. However, I have come across the desire to be able to be able to template over a type that is an enum for writing a library.

Basically the idea is to add the ability to do the following:

fn foobar<T: enum> (x: T)

or

fn foobar<T: enum()> (x: T)

This would mean (in the first case) that it accepts any enum that is unit-like and (in the second case) that may not be unit-like.

Usage: This would allow the user of the functions or structs to specify his own enum type and the library writer can write assuming certain conditions. These could be used for ordering or labeling purposes without knowing how many values within the enum are specified.


#2

Exactly what kind of conditions would this enable that regular trait bounds couldn’t, and/or why would you want to use it instead of regular trait bounds?


#3

This sounds like the exact sort of thing that custom derives were made for. Basically, a custom derive takes the textual definition of whatever #[derive(YourTrait)] is stuck on, and lets you run code to generate impl YourTrait for MyType { /* ... */ } automatically. Pretty neat, though understandably it’s rather hard to get started with.


#4

The obvious requirement would be for the ability to use it as a key in some hash table but that would not be strong enough. I would also like the ability to specify the use of a enum so that the user of the library that special values will be used (the underlying values of an enum) but for them to use the names.


#5

I still somehow don’t get the motivation behind it. What are you trying to do with it? Why is the ability to put in a hash table an “obvious” requirement, and why isn’t a Hash + Eq trait bound good enough for expressing that?


#6

Maybe try presenting an example of some templated enum code vs a non-templated version to give a better feel of what this accomplishes. Something real. Not just foobar.


#7

Pest uses something similar:

pub trait RuleType: Copy + Debug + Eq + Hash + Ord {}

impl<T: Copy + Debug + Eq + Hash + Ord> RuleType for T {}

The expectation when generic over RuleType is that the type is a C-like enumeration. But as specified in the trait bounds, that’s not a hard requirement; any type deriving all of the built-in derives works. (Actually, I should check if we use Ord, even though we can’t remove it.)


#8

Just out of curiosity, what happens if RuleType isn’t a C-style enum?


#9

Absolutely nothing special, although some key types that are supposed to be relatively small may end up not being small.

Since we’re working off of the listed bounds, that’s all that we can rely on generically.

And actually, IIRC, I don’t think the RuleType bounds are actually used for anything, as most of the interesting code using the rule type is derived for a specific rule type.


#10

I guess it is more of a desire thing. Even if it is just a trait, named, or something similar that only enums can and do implement.

As for a concrete example, I was trying to do the design for a synchronization library for stucts based on function and I want the user to be able to provide an enumeration to describe each of the functions.


#11

If you need the user to provide a description of each function, why would you even care if they did it with an enum or a struct? You won’t be able to interact with it in either case.


#12

This feels like it would be better covered as part of an early idea of treating enum variants as regular types (that is, you could refer E::A { prop: u32 } as individual E::A type and so on.