Open raveesh-me opened 4 years ago
We got closer in 2.14 with this. There is an Enum
base class that exposes an index
property.
CC @lrhn if there is anything left here of if we could/should close
With the Enum
superclass we can do the toJson
method. With a hopefully up-coming name
getter on Enum
, we can even do it efficiently (without using split
or even any new allocation).
We still can't access the values
of an enum type given a type variable, which is needed for fromJson
.
It's a feature we can consider, say as a static List<T> valuesOf<T extends Enum>()
on Enum
.
The risk is that it might make tree-shaking the values
list of enum classes less efficient.
The benefit is that it allows methods like fromJson
or a general efficient class EnumSet<T extends Enum>
It's not something we're working actively on, and it does require compiler/back-end support.
I can use enum generic for simple case:
abstract class Layout<B extends Enum> {
abstract final Map<B, double> breakpoints;
}
enum MaterialBreakpoint { sm, lg }
class MaterialLayout extends Layout<MaterialBreakpoint> {}
enum BootstrapBreakpoint { sm, lg, xl }
class BootstrapLayout extends Layout<BootstrapBreakpoint> {}
Now, I want to have common methods on these enums, I must do it like this:
extension MaterialBreakpointExt on MaterialBreakpoint {
bool operator <(MaterialBreakpoint breakpoint) => index < breakpoint.index;
bool operator >(MaterialBreakpoint breakpoint) => index > breakpoint.index;
}
extension BootstrapBreakpointExt on BootstrapBreakpoint {
bool operator <(BootstrapBreakpoint breakpoint) => index < breakpoint.index;
bool operator >(BootstrapBreakpoint breakpoint) => index > breakpoint.index;
}
How could I allow inheritance for enums in the example above? The code snippet below explains what I mean. In the snippet, I use comparison as an example, but I mean arbitrary methods in general.
abstract enum Breakpoint {}
extension BreakpointExt<T extends Breakpoint> on T {
bool operator <(T breakpoint) => index < breakpoint.index;
bool operator >(T breakpoint) => index > breakpoint.index;
}
enum MaterialBreakpoint extends Breakpoint { sm, lg }
bool compareBreakpoints() {
return MaterialBreakpoint.sm > MaterialBreakpoint.lg;
}
@nguyenxndaidev, if you're problem is that you don't want to write another extension for each enum, can you use on Enum
?
extension Comparison<T extends Enum> on T {
bool operator <(T other) => index < other.index;
bool operator >(T other) => index > other.index;
}
enum Letters {a, b, c}
enum Colors {red, green, blue}
void main() {
print(Letters.a > Letters.b); // false
print(Letters.a < Letters.b); // true
print(Letters.a > Colors.red); // error, type mismatch
}
@Levi-Lesches In the snippet, I use comparison as an example, but I mean arbitrary methods in general.
I don't want to make these extension methods for all enums, only on specific enums. These enums are defined by users, not me (owner of the library). That's why I don't want to use extends Enum
and on Enum
.
// in your library
bool lt<T extends Enum>(T a, T b) => a.index < b.index;
bool gt<T extends Enum>(T a, T b) => a.index > b.index;
// in the user's code extension on Letters { bool operator <(Letters other) => lt(this, other); bool operator >(Letters other) => gt(this, other); }
enum Letters {a, b, c} enum Colors {red, green, blue}
void main() { print(Letters.a > Letters.b); // false print(Letters.a < Letters.b); // true print(Letters.a > Colors.red); // error, type mismatch print(Colors.red > Colors.green); // error, Colors doesn't have > }
- Enums are just collections of constants. If you want them to mean something more than that (ie, have arbitrary methods available for some types), just make them actual classes with static constants (an "enum-like class")
Could you give me a code snippet? Note that, the list of values in user defined enum-like class in are different.
- You can define functions and allow the user to apply them on extensions themselves:
This option doesn't make sense to me.
Could you give me a code snippet?
What I'm trying to say is, without context, it sounds like you're trying to do too much with enums (you've mentioned "inheritance", "arbitrary methods", "defined by the user", and "generics"). After all, concepts like inheritance and subtypes don't really apply to enums.
Note that, the list of values in user defined enum-like class in are different.
Not sure what you mean by this -- static const
values are identical to enums for practical purposes. Perhaps something like this for your example:
class MaterialBreakpoint {
final int index;
final double size;
const MaterialBreakpoint(this.index, this.size);
bool operator <(MaterialBreakpoint other) => index < other.index;
bool operator >(MaterialBreakpoint other) => index > other.index;
static const sm = MaterialBreakpoint(0, 10);
static const lg = MaterialBreakpoint(1, 20);
}
class BootstrapBreakpoint extends MaterialBreakpoint {
final String device;
const BootstrapBreakpoint(int index, double size, this.device) : super(index, size);
static const xl = BootstrapBreakpoint(2, 30, "Web on Desktop");
}
void main() {
print(MaterialBreakpoint.sm < MaterialBreakpoint.lg);
print(BootstrapBreakpoint.lg > MaterialBreakpoint.sm);
}
If we add something like #158, we may also allow enum declarations to implement interfaces. Then you can do:
enum MaterialBreakpoint implements OrderedEnum {
lg, sm;
}
abstract class OrderedEnum {
int get index;
}
extension OrderedEnumOrder<T extends OrderedEnum> on T {
bool operator <(T other) => index < other.index;
bool operator >(T other) => index > other.index;
bool operator <=(T other) => index <= other.index;
bool operator >=(T other) => index >= other.index;
}
@Levi-Lesches Thanks for your suggestions! I will see if I can wrap enum inside an abstract class before enum in dart becomes more powerful.
@lrhn your solution is what I need. The key is to allow enum to implement an interface. I hope that it will be added to Dart soon.
This is the test case I want to satisfy:
highlight:
I want to write a converter that can take the type of enum and it is impossible to get the enum interface in the type.
In my ideal case scenario, a solution like this should have worked:
Unfortunately, casts like
JSON as EnumItemInterface
are not as mindless in dart and I am met with an error:Enums and items in the enums already implement a fixed interface. Just exposing those interfaces in the SDK will give me enough to work with, enabling generic programming with enum classes.
A way to impose interfaces on top of classes that we know have that interface but are cast as not having it would also be cool.