0

I have an integer I want to turn into an enum in Dart. I want to do this with generics so I don't have to write the same code again and again for each possible kind of enum.

I know how to do this for one particular kind of enum, per this answer, by using the index operator [] like so

T get notQuiteGenericEnumGetter {
    int i = fromSomeplace();
    if (T == MyEnum) {
        return MyEnum.values[i] as T;
    }else if (T ==
    // tests for other sorts of enumes
}

But what I really want is this done generically so I don't need a long list of if-statements, one for each possible enum. I'd rather do something like this using generics.

T get genericEnumGetter {
    int i = fromSomeplace();
    if (T == Enum) {
        return T.values[i] as T;
    }
}

But this doesn't work if I spell enum as "enum" (undefined name), or as "Enum" (getter values isn't defined for type Type).

I also tried return (T as Enum).values[i] as T; and I'm told the getter 'values' isn't defined for the type 'Enum', which makes me wonder how MyEnum.values worked.

So I guess my question is whether the idea of converting an int to an enum without explicitly testing for the flavor of enum is hopeless, or if there's some approach that works generically for converting integers into enums.

Chris Nadovich
  • 202
  • 1
  • 7

1 Answers1

1

What you're trying to do is not possible for multiple reasons.

  • Even for non-Enum classes, T.anything can never work because static members are not part of the class's interface in Dart. static members are essentially syntactic sugar for globals. The automatically generated values list for Enum types are no different.

  • Dart currently does not allow generic getters.

Even if Dart did allow generic getters (or if you changed it to a normal generic function instead), you'd need to explicitly specify the Enum type name (where would it get inferred from?), at which point you might as well type MyEnum.values[i], which is only slightly more inconvenient.

I also tried return (T as Enum).values[i] as T; and I'm told the getter 'values' isn't defined for the type 'Enum', which makes me wonder how MyEnum.values worked.

Enum is the base type types that declared with enum. Enum itself has no values member; Enum has no values! Only the concrete types declared with enum have the synthesized values members. (Also see Where is "values" defined in a List of enum?)

jamesdlin
  • 81,374
  • 13
  • 159
  • 204
  • Thanks, I suspected it wasn't possible with Dart's enum machinery today. Not that it isn't possible, ever. Who knows what tomorrow may bring? Till then, I'll just eschew "caseless" polymorphic programming for a moment and include all the various if and case statements. Thanks for the nice explanation. I thought it was something like that. – Chris Nadovich Apr 27 '23 at 17:19
  • Before I let this go @jamesdlin, could you comment on how it is that jsonEncode and jsonDecode manage to serialize any sort of enum and deserialize them to the correct type of enum so long as they have ```toJson``` and ```fromJson``` methods? Is there any way I could use that same magic here? If I had such methods, could I generically invoke T.toJson and T.fromJson or equiv? It just bugs me that I need a case statement. OOP is supposed to always have a way around case statements. – Chris Nadovich Apr 27 '23 at 17:52
  • @ChrisNadovich `toJson` would never be a `static` method. `toJson` should always be an *instance method*, and there is no magic required for that: `jsonEncode` simply tries calling `toJson` on every object to serialize. I don't see how `fromJson` could work for `enum`s; either the JSON would store it as a string or as an integer value, and there's no way for `jsonDecode` to know that it should decode that as anything other than a string or integer. Can you provide a working example? – jamesdlin Apr 27 '23 at 18:24
  • Ahh, I see, @jamesdlin, now that I look more closely at jsonEncode/Decode I see they can't do polymorphism either. At each layer the classes being serialized must know exactly what types they are encoding or decoding. Nevertheless, this question still frustrates me. The machine somehow knows the run-time enum type to the extent that I can write a switch or if(T==MyEnum) statement to call the correct method for that generic type, but there doesn't seem to be a way the ask the generic object T itself to call the correct method for its own type. – Chris Nadovich Apr 27 '23 at 19:57