Closed lukepighetti closed 2 years ago
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 String
s, 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
,name
andvalues
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}');
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).
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 .
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 Enum
s 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
Admin comment by @mit-mit:
This request is being investigated as a feature. We've investigating a general mechanism for adding members (fields, methods, an unnamed const constructor) to enums, for example:
For details, see the working proposal feature specification: https://github.com/dart-lang/language/blob/master/accepted/2.17/enhanced-enums/feature-specification.md
Original feature request by @lukepighetti:
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?
Dart
TypeScript