Enums in Dart require a lot of additional tooling to extract all of their utility in a production app. One of those features is mapping Enums to string. One can use a Map, but since the dart language server doesn't have the ability to report the contents of a map to IDE tools, it is not a good option for self-documenting APIs.
I believe TypeScript handles this by replacing the integer with a string when specified. Would it be possible to do the same in Dart?
enum Time {
hour,
day,
week,
month,
year
}
_timeToString(Time time){
switch (time) {
case Time.hour:
return "1h";
case Time.day:
return "1d";
case Time.week:
return "1w";
case Time.month:
return "1m";
case Time.year:
return "1y";
default:
return "1h";
}
}
enum Time {
hour = "1h",
day = "1d",
week = "1w",
month = "1m",
year = "1y"
}
Just FYI, a similar topic has been on the radar a while ago, e.g., here: https://github.com/dart-lang/language/issues/83#issuecomment-449380965.
Thanks for letting me know, if this thread is still of use to anyone, I would propose a syntax like so. Not sure how Darty it is.
enum Time<String> {
hour = "1h",
day = "1d",
week = "1w",
month = "1m",
year = "1y"
}
In Java, any enum instance could have its own field variables, methods, and could even implement abstract methods.
The values could be passed in to the enum constructor.
public enum MyEnum {
COLD(0),
WARM(24),
HOT(37);
private final int temperature;
private MyEnum(int temperature) {
this.temperature = temperature;
}
}
Any reason why a single template variable would be preferable to that sort of solution?
Note: I don't know how Dart works, just asking :smile:
The bulk of my experience is in TypeScript and they allow a similar thing to what you describe. I personally have no need to have enums return methods, but I certainly have nothing against it!
@Zhuinden If I recall correctly, this was debated in pre-Dart 1 days and some people were opting for simplicity and against Java style enums.
I personally think that an enum should be able to store const values at a minimum. I just end up writing so much "convert this enum to strings" functions that get colocated with my enums. I can see the argument for keeping it simple but I see nothing wrong with allowing the association with const values.
An alternative is to add a method to enums that outputs the index or the string. So myEnum.foo.toString() would produce foo, which would make it a lot more useful.
Also, enums really should allow leading numbers, but that may be a different issue.
myEnum {
1m: Duration(minutes: 1),
15m: Duration(minutes: 15),
1h: Duration(hours: 1),
}
This would have saved me an extraordinary amount of time the other day especially if myEnum had methods like myEnum.keys, myEnum.values, myEnum.from(Duration duration)
Shame, they are missing out, although now with Kotlin I'd favor sealed class in many scenarios where people used enum abstract methods.
But storing simple const values? Totally reasonable I think. You shouldn't have to build a map for each associated value.
I have noticed that Dart seems to value simplicity over sugar. I personally value sugar over simplicity since sugar is optional. But I get where they are coming from. There is a lot of value in simplicity.
I'm currently using classes full of static const Strings, but the only downside I'm having with this is that when I declare the Type of a param that's going to accept this "enum" it has to be String and not the class name.
Wouldn't it be simple to just make enum extendable, and allow the basic usage to continue to allow for backwards compatibility but then give us the ability to add our own submethods like .toString() etc?
Maybe something more simillar to current dart syntax but much more practical:
enum Time(String this.yourCustomValue) {
hour("1h"),
day("1d"),
week("1w"),
month("1m"),
year("1y");
final String yourCustomValue;
}
Define variables by this way gives you an opportunity to declare more than one value to enums :)
Just learned about how swift handles enums and I find it to be a good solution
// Enums can optionally be of a specific type or on their own.
// They can contain methods like classes.
enum Suit {
case spades, hearts, diamonds, clubs
func getIcon() -> String {
switch self {
case .spades: return "♤"
case .hearts: return "♡"
case .diamonds: return "♢"
case .clubs: return "♧"
}
}
}
// Enum values allow short hand syntax, no need to type the enum type
// when the variable is explicitly declared
var suitValue: Suit = .hearts
// String enums can have direct raw value assignments
// or their raw values will be derived from the Enum field
enum BookName: String {
case john
case luke = "Luke"
}
print("Name: \(BookName.john.rawValue)")
The example goes on to include other unique features of Swift enums which I don't think we should consider for Dart.
For dart I would rewrite the two examples like so:
enum Suit<IconData> {
spades = Icons.spade,
hearts = Icons.heart,
diamonds = Icons.diamond,
clubs = Icons.club,
}
enum BookName<String> {
john,
luke = "Luke",
}
I know these start to blur the line between enums, structs, and maps, but it's food for thought.
@lukepighetti How do you want to declare 2 or more values to the enum? Eg. for enum Gradient(start, middle, end)?
Gradient is kinda heavyweight but I would imagine something like this (from Flutter)
enum AppGradient<Gradient> {
murica: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: <Color>[Colors.red, Colors.white, Colors.blue],
stops: <double>[0.0, 0.5, 1.0],
),
canuckistan: LinearGradient(
begin: Alignment.bottomCenter,
end: Alignment.topCenter,
colors: <Color>[Colors.red, Colors.white, Colors.red],
stops: <double>[0.0, 0.5, 1.0],
),
}
but as you can see it gets closer to a static class, i'm not sure i would use it this way. My desire to have a enum map to something like a string is so that it's easy to build an enum from something like a json response
II constantly find myself using the following helper methods when interfacing with the outside world:
String enumToString(o) => o.toString().split('.').last;
T enumFromString<T>(Iterable<T> values, String value) {
return values.firstWhere((type) => type.toString().split('.').last == value,
orElse: () => null);
}
I also favor enums over static classes like Colors.white because the code editor is not able to help me with the possible options. It's a big help to see right in my editor what 3 options a function arg could take.
Wouldn't it be easier just user Maps?
Map<String, String> values = {
"hour": "1h",
"day": "1d",
"week": "1w",
"month": "1m",
"year": "1y"
};
main() {
print(values['day']); // 1d
print(values.keys); // (hour, day, week, month, year)
print(values.values); // (1h, 1d, 1w, 1m, 1y)
}
@kgbsmurf it is safer and more clear to use enums. if in your example day would not exist, you would not get any value. If you use an enum you know exactly what values exist and which not. (And also it is more nice to have auto-completion, so actually the same reason)
Good point. Thank you.
Maps do not work with static analysis like they do in a language like typescript (iirc)
Yea enums provide more type safety than maps.
I had the same issue while back, I think it's a much needed feature. I've developed a helper class library which might help few people having same issue Vnum
Has support for enum values, extensions, serialization, comparison, etc.
You can define it like :
@VnumDefinition
class CarType extends Vnum<String> {
/// Cases
static const CarType sedan = const CarType.define("sedan-value");
static const CarType suv = const CarType.define("suv-value");
static const CarType truck = const CarType.define("truck-value");
static const CarType none = const CarType.define("unknown");
/// Constructors
const CarType.define(String fromValue) : super.define(fromValue);
factory CarType(String value) => Vnum.fromValue(value,CarType);
/// (optional) Add these constructors if serilization is supported
dynamic toJson() => this.value;
factory CarType.fromJson(dynamic json) => CarType(json);
/// Extend your Vnums
String color(){
if (value == CarType.sedan.value) {
return "Green";
}else if (value == CarType.suv.value) {
return "Orange";
}else if (value == CarType.truck.value) {
return "Yellow";
}
return "Unknown";
}
}
and use it as below:
var car = CarType.sedan;
var carValue = car.value;
var carFromValue = CarType('suv-value');
var nonExisting = CarType('rocket') /// returns null
/// Vnum functions
var color = car.color() /// returns "Green"
/// Iterating cases
var allCases = Vnum.allCasesFor(CarType);
print(allCases.length); /// prints 4
Just learned about how swift handles enums and I find it to be a good solution
Agreed! I'm a huge fan of another aspect of Swift's enums that hasn't been mentioned: associated values.
enum LoadingState {
case loading
case loaded(Data)
}
switch loadingState {
case .loading:
print("Still loading...")
case .loaded(let data):
print("Loaded data: \(data)") // access to `data` as non-optional strongly-typed `Data`
}
Enums with associated values are an excellent solution for eliminating invalid state and better describing real-world scenarios concisely.
I'm new to Dart, but this is a language feature I'd love to see! I'm not sure if this is feasible, or what the Dart syntax would look like. Any ideas?
Enums with associated values are an excellent solution for eliminating invalid state and better describing real-world scenarios concisely.
I'm new to Dart, but this is a language feature I'd love to see! I'm not sure if this is feasible, or what the Dart syntax would look like. Any ideas?
See #546 for some relevant context.
If dart has this feature, it would better describe the states of bloc. Currently, we are use classes to describe it. It not really concise.
Maybe you can consider referring swift's enum associated value.
Example
enum Counter {
case start(Int)
case pause(int)
case stop(int)
}
Hi,
I do prefer to have an enum that placing a values of string or other datatypes just like typescript.
but for workaround I just like to share my approach to this:
class Spacing {
static int get xs => 4;
static int get s => 8;
static int get m => 16;
static int get l => 24;
static int get xl => 32;
}
but I do really hope to have an enum that holds specific values in dart. thanks!
Is it possible to also add index, name and values properties to the Enum?
enum Color {
white,
green,
blue
}
var color = Color.green;
print('index: ${color.index}');
print('name: ${color.name}');
print('values: ${color.values}');
index: 1
name: green
values: [Color.white, Color.green, Color.blue]
At the moment I have to define an extension for each enum class because defining an extension directly on the enum type is not supported.
Is it possible to also add
index,nameandvaluesproperties to the Enum?enum Color { white, green, blue } var color = Color.green; print('index: ${color.index}'); print('name: ${color.name}'); print('values: ${color.values}');Expected output
index: 1
name: green
values: [Color.white, Color.green, Color.blue]At the moment I have to define an extension for each enum class because defining an extension directly on the enum type is not supported.
That does not make much sense since Color.green return a color object, which has nothing to do with Enum. So I don't how they can tie it together like this
That does not make much sense since Color.green return a color object, which has nothing to do with Enum. So I don't how they can tie it together like this
It was an example, you can easily replace Color with Cat:
enum Cat {
white,
green,
blue
}
var cat = Cat.green;
print('index: ${cat.index}');
print('name: ${cat.name}');
print('values: ${cat.values}');
Expected output
index: 1
name: green
values: [Cat.white, Cat.green, Cat.blue]
@vladostaci Note that this:
print('index: ${cat.index}');
print('name: ${cat}');
print('values: ${Cat.values}');
would print
index: 1
name: Cat.green
values: [Cat.white, Cat.green, Cat.blue]
so basically what you expect with the exception of the name (which is prefixed by enum name).
Right now, enum type in dart is just a set of tokens. What this issue is asking for is to provide a simple way of mapping each token to some (associated) value of a different type (String, int, Foo, etc).
That is, the difference between what we have and what we need is the difference between a set and a map. If this is so, then there's a rather straightforward (and backward-compatible) way to expand the syntax by intentionally making it look like a map literal:
enum Day of String {
monday: "Monday",
tuesday: "Tuesday",
// etc.
}
var d = Day.monday;
print(Day[d]); // Monday
print(Day.values); // ["Monday", "Tuesday", ...]
print(Day.keys); // [Day.monday, Day.tuesday, ...]
If "of" clause is omitted, compiler associates each value with itself (so enum E is treated as enum E of E). Due to this, Cat.values in the example from the previous comment will still print [Cat.white, Cat.green, Cat.blue]
How about that?
EDIT: in addition to (or instead of) Day[d], we can have a more convenient getter d.value (retrieve a value assotiated with enum token)
any update on this request?
No update. The language team is very focused on NNBD, so almost all other language changes will be moving very slowly until that's done. :)
No update. The language team is very focused on NNBD, so almost all other language changes will be moving _very_ slowly until that's done. :)
What is NNBD?
non nullable by default types
why don't you all just:
class Channels {
static final String posts = 'posts',
livestreams = 'livestreams',
messages = 'messages',
events = 'events';
}
after that I can use it like enums: Channels.posts. easy 🤔
Because that doesn't allow you to use a switch statement and have the
analyzer warn you of missing cases.
On Sun, 29 Dec 2019, 12:41 Rebar Ahmad, notifications@github.com wrote:
why don't you all just:
class Channels {
static final String posts = 'posts', livestreams = 'livestreams', messages = 'messages', events = 'events';}
after that I can use it like enums: Channels.posts. easy 🤔
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
https://github.com/dart-lang/language/issues/158?email_source=notifications&email_token=AAARSP4DQSZGXKJKDNKNCIDQ2753PA5CNFSM4GMSLBC2YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHYVYMQ#issuecomment-569465906,
or unsubscribe
https://github.com/notifications/unsubscribe-auth/AAARSPYRD37UXKMTW53BJATQ2753PANCNFSM4GMSLBCQ
.
after that I can use it like enums: Channels.posts. easy 🤔
This may work in practice, but not in theory.🤔
I just create a python like class :
class UserType {
static String individual = 'individual';
static String business = 'business';
}
Then use it as an enum UserType.individual
The issue with a class used as namespace to store static final variable is, with something like this:
class MyEnum {
static final something = 'something';
static final somethingElse = 'somethingElse';
}
(or using integers instead of strings if that's your thing)
Then type system becomes useless.
We don't manipulate an object of type "MyEnum" anymore, but instead a "String".
Which means that if you have a function which takes an instance of that enum as parameter, we'd have:
void myFunction(String value) {}
Instead of:
void myFunction(MyEnum value) {}
That's poor in readability (the dev using myFunction doesn't know that he you should strings from the namespace MyEnum).
And it's not type safe. We could write the following for example: myFunction('invalid value'), which shouldn't be allowed.
Extensions may partially solve this problem:
enum Entity { SHIP, PORT }
extension EntityExtension on Entity {
static String _value(Entity val) {
switch (val) {
case Entity.SHIP: return "ship";
case Entity.PORT: return "port";
}
return "";
}
String get value => _value(this);
}
And analyzer warns about missing cases, just don't add default to switch 😁
Extensions may partially solve this problem:
enum Entity { SHIP, PORT } extension EntityExtension on Entity { static String _value(Entity val) { switch (val) { case Entity.SHIP: return "ship"; case Entity.PORT: return "port"; } return ""; } String get value => _value(this); }And analyzer warns about missing cases, just don't add default to switch 😁
I don't think so. I have so many Enums in my code and I don't want to create a extenssion for all of the enums in my code. Nothing is better than Language support for this feature!
@pedromassango sure thing language support will be better option. But extensions is perhaps the best possible workaround for current moment. And stub for switch cases is generated by IDE, so not much to manually type.
I definitely vote for language supported enums with values, constructor and additional methods like
enum BaseUnit {
current ( 'A', 'ampere' ),
length ( 'm', 'meter' ),
luminosity ( 'cd', 'candela' ),
mass ( 'kg', 'kilogram' ),
substance ( 'mol', 'mole' ),
temperature ( 'K', 'kelvin' ),
time ( 's', 'second' );
/// Instance variables are final.
final String code, name;
/// Constructor. Could be dropped if integrated into compiler ?!?
BaseUnit( this.code, this.name ) {};
/// Finds enum by given code or returns `null`
/// Could all methods of an enum be automatically static?
static BaseUnit findByCode( String code ) {
for ( BaseUnit enumEntry in BaseUnit.values ) {
if ( enumEntry.code == code ) return enumEntry;
}
return null;
}
}
Quite often I have to build frontends for databases which are already filled. So I find columns like
''gender'' containing 1 for male, 2 for female and -1 for unknown. To make code readable, I would like to have an enum like above:
enum Gender {
unknown ( -1 ),
male ( 1 ),
female ( 2 );
final int code;
Gender( this.code );
static Gender findByCode( int code ) {
for ( Gender enumEntry in Gender .values ) {
if ( enumEntry.code == code ) return enumEntry;
}
return null;
}
}
The package generic_enum might be of interest. It supports building enumeration classes with generic value type and json-serialization.
Technologies such as built_value uses an EnumClass, which works well, but it heavily reliant on serialization/deserialization and code generation to do all it's magic (processing classes into strings), which is quite a lot of overhead.
I recommend it if you also require immutability... not otherwise.
Please don't forget about the numbers, it very common to have enums like this as well:
C#
public enum LanguageEnum
{
NL = 1,
EN = 2,
DE = 4,
TR = 8,
FR = 16,
ES = 32,
IT = 64
}
Or Typescript
export enum LanguageEnum {
NL = 1,
EN = 2,
DE = 4,
TR = 8,
FR = 16,
ES = 32,
IT = 64
}
It should allow for easy conversion from number to enum when, for example, using the json serializer, so I suggest a int myNum = 5; var language = myNum as LanguageEnum should be possible.
Honestly it should be able to handle any kind of value.
Any news on this issue? it already experimental?
surprised this hasn't been resolved as yet. Would be nice getting this feature sooner than later.
This is part of #546. Ultimately, it's just a request for union types.
There are multiple third-party code-generators that help with it in the meantime.
I hope this feature will be implanted, this is used on most of other famous languages and this some examples
python
class DocAction(enum.Enum):
Complete = 'CO'
WaitComplete = 'WC'
Approve = 'AP'
Reject = 'RJ'
Java
public enum DocAction {
Complete("CO"),
WaitComplete("WC"),
Approve("AP"),
Reject("RJ");
}
private final String value;
public final String getValue() {
return value;
}
private DocAction(String value) {
this.value = value;
}
}
dotNet use also the principal of extension
public enum DocAction {
Complete,
WaitComplete,
Approve,
Reject,
}
public static class DocActionExtensions {
public static string GetValue(this DocAction docAction) {
switch (docAction) {
case DocAction.Complete:
return "CO";
case DocAction.WaitComplete:
return "WC";
case DocAction.Approve:
return "AP";
case DocAction.Reject:
return "RJ";
default:
return "--";
}
}
i think extension is the close solution
Hey @dernoun,
You could already use the extension approach with Dart
yes i did @jogboms
Dart
enum DocAction {
Complete,
WaitComplete,
Approve,
Reject,
}
extension DocActionExtension on DocAction {
static String _value(DocAction val) {
switch (val) {
case DocAction.Complete:
return "CO";
case DocAction.WaitComplete:
return "WC";
case DocAction.Approve:
return "AP";
case DocAction.Reject:
return "RJ";
}
}
String get value => _value(this);
}
but like @pedromassango said: "Nothing is better than Language support for this feature!"
just as a note you can get rid of those break; lines in your example if you so desire
I would like to change the subject from "_Allow enums to store numbers or strings_" to "Allow enums to be fully functional".
If some extended functionality for enums became part of Dart then it would be great to have it fuly functional. There are a couple of examples which only extends an enum value with an int or string.
This kind of "_union_" will not cover:
To achieve these, an enum should be implemented as a standard class with a fixed number of unmodifiable instances with final variables of any type.
Example for physical units (not all of them covered):
enum SIBase { Temperature, Mass, Length }
enum Unit {
SIBase base; String code; double factor;
Meter( Length, 'm', 1.0 ),
Kilometer ( Length, 'km', 1_000 ),
LightSecond ( Length, 'ls', 299_792_458 ),
Gram ( Mass, 'gr' ),
Kilogramm ( Mass, 'kg' );
// private constructor
_Unit( this.base, this.code )
// Get Unit or return null
Unit getByCode( String code ) {
for ( Unit unit in Unit.values() ) {
if ( code == unit.code ) { return unit; }
}
return null;
}
List<Unit> getSelection( SIBase base ) {
List<Unit> unitList = [];
for ( Unit unit in Unit.values() ) {
if ( unit.base == base ) { unitList.add( unit ); }
}
return unitList;
}
This allows to have the code (get selection) close to the data (enums.
Where _Unit is something like a private constructor. It is only required to state the order of parameters for the instances. Maybe there is more elegant solution for this.
You can get exactly that API today just using extensions:
enum SIBase { Temperature, Mass, Length }
enum Unit {
Meter,
Kilometer,
LightSecond,
Gram,
Kilogramm,
}
extension UnitMembers on Unit {
SIBase get base => const {
Unit.Meter: SIBase.Length,
Unit.Kilometer: SIBase.Length,
Unit.LightSecond: SIBase.Length,
Unit.Gram: SIBase.Mass,
Unit.Kilogramm: SIBase.Mass,
}[this];
String get code => const {
Unit.Meter: 'm',
Unit.Kilometer: 'km',
Unit.LightSecond: 'ls',
Unit.Gram: 'gr',
Unit.Kilogramm: 'kg',
}[this];
double get factor => const {
Unit.Meter: 1.0,
Unit.Kilometer: 1000,
Unit.LightSecond: 299792458,
Unit.Gram: ???,
Unit.Kilogramm: ???,
}[this];
// Why is this an instance member?
Unit getByCode(String code) => const {
'm': Unit.Meter,
'km': Unit.Kilometer,
'ls': Unit.LightSecond,
'gr': Unit.Gram,
'kg': Unit.Kilogramm,
}[this];
List<Unit> getSelection( SIBase base ) {
List<Unit> unitList = [];
for ( Unit unit in Unit.values() ) {
if ( unit.base == base ) { unitList.add( unit ); }
}
return unitList;
}
}
There is a valid argument that the syntax to do so is tedious, but the fundamental capabilities are all there.
@munificent OK. I would accept this approach as an answer to a question on StackOverflow. Anyway I agree with you that it looks a bit tedious.
@hlemcke I try to write proposals that cover low hanging fruit. I think Munificent's option is reasonable given your use case.
Plus @munificent's answer is could also be code generated to make it less tedious
I am liking this extension to enum. the rest of the code uses the enum class only. and this a god send for json conversions from apis to something more useful!
Why is the original issues still open? It should be closed with the extension as the solution as the get methods allow both numeric and string representations of the same enum making it much more flexible than other languages.
@munificent it's pretty good that we can use extensions for that, but this approach doesn't use static analyzer benefits. For example, if you add any new value to Unit enum
enum Unit {
Meter,
Kilometer,
LightSecond,
Gram,
Kilogramm,
Liter, // new value
}
The compiler will not give you a hint that you should update the extension as well. The workaround is to use a switch without default, in that case, it gives you a good compile-time error, at least in "DartPad with null safety". But, in this case, code is too verbose. Also, we can use extensions for static methods like getByCode, but in that case, you should call them from extension and not from enum, and that's not very convenient. That's would be great if this will be part of the syntax, so these limitations will no longer a thing, especially if this can be done in the frontend and use extensions under the hood.
My full example:
main() {
print(Unit.Kilometer.code);
print(UnitUtils.getByCode('km'));
}
enum Unit {
Meter,
Kilometer,
LightSecond,
Gram,
Kilogramm,
Liter,
}
extension UnitUtils on Unit {
String get code {
switch(this) {
case Unit.Meter: return 'm';
case Unit.Kilometer: return 'km';
case Unit.LightSecond: return 'ls';
case Unit.Gram: return 'gr';
case Unit.Kilogramm: return 'kg';
case Unit.Liter: return 'l';
}
}
static Unit getByCode(String code) {
switch(code) {
case 'm': return Unit.Meter;
case 'km': return Unit.Kilometer;
case 'ls': return Unit.LightSecond;
case 'gr': return Unit.Gram;
case 'kg': return Unit.Kilogramm;
case 'l': return Unit.Liter;
default: return Unit.Meter;
}
}
}
@nvsravank The extension to enum method is a good way if you need different types. But when you only want to store String e.g. for an http api then it's a lot of duplicated code. You need to create the extension class + method + the switch case what leads to duplicated code lines in comparison to other programming languages like Kotlin or even Java - and this is a really bad thing.
Only for receiving the String from the enum, when i search the Enum from the String value i have triple the code ...
Just encountered the same problem

I can easily do it in C#, but not working in Dart.
Can get around this with static members though:

@subzero911 for this particular use case (sequential indices starting at 0) you can just use index property of enum values.
@subzero911 for this particular use case (sequential indices starting at 0) you can just use
indexproperty of enum values.
No, it's not sequential. It's custom server error codes (non-standard).
Next value is 101,102, 103, then 200, 201 etc.
This is one of the features that I think Dart is missing the most. The existing workarounds are either verbose (utility/extension methods) or break static analysis (using a class with static constants), and none are optimal from an organizational standpoint since they require code to be written that is declared separately from the enum type itself. This gets especially cumbersome when working with an API that uses enums for various fields; since there is no easy way to convert between an arbitrary value and an enum value, it requires manual conversion methods to be made for every declared enum type.
This is also related to the other missed (though less common) feature to use enums as bit fields as described in this issue. It's a pretty common feature in many other programming languages both mature and cutting-edge that enums are more than just syntactic labels and can represent actual usable data that can be worked with and operated on, and as much as I like Dart as a language, this is one area where it is seriously dropping the ball.
Null checking and other features take priority right now, but I hope value enums and/or enum class members are tackled soon after.
ADT and enums with values are extremely useful! They give your ability to describe and structure the shape of your data pretty well. Structures can be deep nested, enums can include other enums and so on. Eventually you'll get well described data of you domain and it can be read like a doc. And once you described it working with well structured data types is pure plessure. You are type safe, pattern matchers don't allow you to miss any case, auto complete feature, etc.
So I'm realy disappointed by the lack of this feature in Dart and look forward for. Please, implement it)
It could be amazing to have ability to have enums with values similar to rust
enum LoadingState{
failed,
loading,
ok(String)
}
then you get value through pattern matching in rust afaik dart doesnt support pattern matching so something like LoadingState.value getter could handle that
I believe that relies on algebraic types. https://github.com/dart-lang/language/issues/349
@lukepighetti I didn't mean that broad of support. Just enums to have associated values shouldn't be horribly difficult with the tools we have at hand already otherwise having static values corresponding to enums I think doesnt add really a lot of value and easily could be handled by a lsp server or ide tools. Something similar to :AddTags functionality of vimgo
In all fairness, having Rust-like support for complex enums would make ADTs extremely easy to implement. It would essentially satisfy the desires for value enums, sealed data classes, and ADTs all to some degree and would make full implementation of each of them much simpler.
If people haven't already, I recommend checking out the freezed package which I mentioned in https://github.com/dart-lang/language/issues/349#issuecomment-584965995
Remi Rousselet, who made the great provider, functional_widget, and flutter_hooks libraries, among others, recently launched the freezed package that includes immutable classes and also algebraic data types, along with an exhaustive when function to switch between the unions.
You can create immutable classes using an abstract class with the @immutable annotation and the specified properties:
@immutable
abstract class Person with _$Person {
factory Person(String name, int age) = _Person;
}
For ADTs, create an abstract class with factories specifying their values, and use when to pattern match them:
@immutable
abstract class Model with _$Model {
factory Model.first(String a) = First;
factory Model.second(int b, bool c) = Second;
}
var model = Model.first('42');
print(
model.when(
first: (String a) => 'first $a',
second: (int b, bool c) => 'second $b $c'
),
); // first 42
There's also maybeWhen, similar to other languages where there is a default case, using the orElse keyword:
@immutable
abstract class Union with _$Union {
const factory Union(int value) = Data;
const factory Union.loading() = Loading;
const factory Union.error([String message]) = ErrorDetails;
}
var union = Union(42);
print(
union.maybeWhen(
null, // ignore the default case
loading: () => 'loading',
// did not specify an `error` callback
orElse: () => 'fallback',
),
); // fallback
It looks to be a pretty cool library. I'm glad that Dart has code generation so that we can create language features via libraries instead of just waiting for them by the official Dart team, although language features would be preferred over libraries of course, if only to cut down the amount of generated code and boilerplate.
I checked freezed recently.
Unfortunately, it doesn't deal with collections: https://github.com/rrousselGit/freezed/issues/185
And it is a serious issue, because it leads to crazy workarounds:

Unfortunately, it doesn't deal with collections: rrousselGit/freezed#185
You're talking about deep copy.
Deep copy is the least likely feature of Freezed to make it in Dart. Very few languages support that and only have the spread operator instead (which Dart already has).
It is very likely that Dart would have the same issue even with Unions/Super enum/...
why can' t i have an extension on enum? i what to create a method that returns particular constant or value of the that enum...... has to be simillar to enum.valueof in java
@Twapa you can have an extension like this:
enum Time {
hour,
day,
week,
month,
year
}
extension TimeExtension on Time{
String get valueOf{
switch (this) {
case Time.hour:
return "1h";
case Time.day:
return "1d";
case Time.week:
return "1w";
case Time.month:
return "1m";
case Time.year:
return "1y";
default:
return "1h";
}
}
}
usage: Time.hour.valueOf
@Twapa you can have an extension like this:
enum Time { hour, day, week, month, year } extension TimeExtension on Time{ String get valueOf{ switch (this) { case Time.hour: return "1h"; case Time.day: return "1d"; case Time.week: return "1w"; case Time.month: return "1m"; case Time.year: return "1y"; default: return "1h"; } } }usage: `Time.hour.valueOf
well thanks for that but what i wanted is this
`enum Time{
monday,tuesday,wednesday
}`
extension valueR on enum{
Time valueOf(String s){
}
}
usage: Time.valueOf("monday''); //this has to return enum constant of Time that is equivalent and in this case monday.....i understand this feature is used alot in java......
@Twapa
It is quite strange that Dart doesn't yet have a built-in function for parsing strings or other values into enum equivalents. In my opinion, it is one of Dart's greatest single weaknesses in its usefulness as a data processing language.
There are two ways to manually create a parsing function: explicit switches or toString finaglement:
Time valueOf(String s) {
switch (s) {
case 'hour': return Time.hour;
case 'day': return Time.day;
case 'week': return Time.week;
case 'month': return Time.month;
case 'year': return Time.year;
}
throw ArgumentError('$s is not a valid Time value');
}
or
Time valueOf(String s) {
for (var time in Time.values) {
final ts = time.toString();
if (ts.substring(ts.indexOf('.') + 1) == s) {
return time;
}
}
throw ArgumentError('$s is not a valid Time value');
}
The second approach is a mostly drop-in solution and is the more condensed version for enums with a lot of values, but it might rub some people the wrong way with how it converts every enum value into a string every time it's called which can get computationally expensive if it's called a lot.
But regardless, whichever implementation you go would have to be implemented on every enum type you want to have this on, and since there's no way to declare static extension methods in such a way that you can call the static method on the extended type (i.e. Time.valueOf), you have to settle for making it a run-of-the-mill utility method. The "cleanest" way might be to still put it in an extension and then reference the name of the _extension_ to call the method:
extension TimeE on Time {
static Time valueOf(String s) {
...
}
}
// usage
TimeE.valueOf('hour');
But of course, at that point, from a practical perspective, there's not really any difference between that and having an unrelated utility class to put the static method in.
@Twapa
It is quite strange that Dart doesn't yet have a built-in function for parsing strings or other values into enum equivalents. In my opinion, it is one of Dart's greatest single weaknesses in its usefulness as a data processing language.
There are two ways to manually create a parsing function: explicit switches or
toStringfinaglement:Time valueOf(String s) { switch (s) { case 'hour': return Time.hour; case 'day': return Time.day; case 'week': return Time.week; case 'month': return Time.month; case 'year': return Time.year; } throw ArgumentError('$s is not a valid Time value'); }or
Time valueOf(String s) { for (var time in Time.values) { final ts = time.toString(); if (ts.substring(ts.indexOf('.') + 1) == s) { return time; } } throw ArgumentError('$s is not a valid Time value'); }The second approach is a mostly drop-in solution and is the more condensed version for enums with a lot of values, but it might rub some people the wrong way with how it converts every enum value into a string every time it's called which can get computationally expensive if it's called a lot.
But regardless, whichever implementation you go would have to be implemented on every enum type you want to have this on, and since there's no way to declare static extension methods in such a way that you can call the static method on the extended type (i.e.
Time.valueOf), you have to settle for making it a run-of-the-mill utility method. The "cleanest" way might be to still put it in an extension and then reference the name of the _extension_ to call the method:extension TimeE on Time { static Time valueOf(String s) { ... } } // usage TimeE.valueOf('hour');But of course, at that point, from a practical perspective, there's not really any difference between that and having an unrelated utility class to put the static method in.
i appreciate for this reply.... you clearly address my question........thanks
i'm a kotlin developer and i use extension extensively to write clean code and I was very excited when I heard that Dart support it, but I was shocked that I couldn't use ContactType.valueOf()
i'm kind of use the idea above but i use describeEnum to subtract the ContactType from values
is there any hope that i can use it directly without using new name to that extension ?
enum ContactType { FACEBOOK, INSTAGRAM, GOOGLE }
extension on ContactType {
String get raw => describeEnum(this);
static ContactType valueOf(String data) {
for (var value in ContactType.values){
if (value.raw == data) return value ;
}
throw ArgumentError("$data is not a valid ContactType value");
}
}
@abdektefane That would be static static extension methods, #723.
This just needs to have value assignments and also needs to work with bitwise operators (flags) if int is specified and it should just work. There should be built in methods to get the value of an enum, parse the enum from a string value of it, and iterate through all values/names of the enum as a map too.
Essentially ALL other languages have this, and it really breaks serialization not having it or causes you to have massive work arounds.
This just needs to have value assignments and also needs to work with bitwise operators (flags) if int is specified and it should just work. There should be built in methods to get the value of an enum, parse the enum from a string value of it, and iterate through all values/names of the enum as a map too.
Essentially ALL other languages have this, and it really breaks serialization not having it or causes you to have massive work arounds.
I agree.
This seems to be so basic in most languages.
@recepkoseoglu That doesn't show how you can store values inside an enum, like an algebraic data type, which is what this issue is about.
Most helpful comment
Thanks for letting me know, if this thread is still of use to anyone, I would propose a syntax like so. Not sure how Darty it is.