Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow enum classes to have members #158

Closed
lukepighetti opened this issue Dec 29, 2018 · 175 comments
Closed

Allow enum classes to have members #158

lukepighetti opened this issue Dec 29, 2018 · 175 comments
Assignees
Labels
feature Proposed language feature that solves one or more problems request Requests to resolve a particular developer problem

Comments

@lukepighetti
Copy link

lukepighetti commented Dec 29, 2018

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:

enum Time2 {
  hour('1h'), 
  day('1d'), 
  week('1w');
  
  final String label;

  const Time2(this.label);

  String toGreeting() => "I'll see you in $label!";
}

main() {
  var t = Time2.day;
  print(t.toGreeting());
}

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

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";
  }
}

TypeScript

enum Time {
  hour = "1h",
  day = "1d",
  week = "1w",
  month = "1m",
  year = "1y"
}
@eernstg
Copy link
Member

eernstg commented Dec 30, 2018

Just FYI, a similar topic has been on the radar a while ago, e.g., here: #83 (comment).

@lukepighetti
Copy link
Author

lukepighetti commented Dec 30, 2018

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"
}

@Zhuinden
Copy link

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 😄

@lukepighetti
Copy link
Author

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!

@ahmetaa
Copy link

ahmetaa commented Jan 3, 2019

@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.

@lukepighetti
Copy link
Author

lukepighetti commented Jan 3, 2019

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)

@Zhuinden
Copy link

Zhuinden commented Jan 3, 2019

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.

@lukepighetti
Copy link
Author

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.

@ThinkDigitalSoftware
Copy link

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.

@ThinkDigitalSoftware
Copy link

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?

@wrozwad
Copy link

wrozwad commented Jun 26, 2019

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 :)

@lukepighetti
Copy link
Author

lukepighetti commented Jul 15, 2019

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.

@wrozwad
Copy link

wrozwad commented Jul 15, 2019

@lukepighetti How do you want to declare 2 or more values to the enum? Eg. for enum Gradient(start, middle, end)?

@lukepighetti
Copy link
Author

lukepighetti commented Jul 15, 2019

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

@venkatd
Copy link

venkatd commented Aug 16, 2019

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.

@kgbsmurf
Copy link

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)

}

@tomkastek
Copy link

@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)

@kgbsmurf
Copy link

Good point. Thank you.

@lukepighetti
Copy link
Author

lukepighetti commented Sep 17, 2019

Maps do not work with static analysis like they do in a language like typescript (iirc)

@kennethnym
Copy link

Yea enums provide more type safety than maps.

@AmirKamali
Copy link

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

https://pub.dev/packages/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

@swain
Copy link

swain commented Oct 18, 2019

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?

@munificent
Copy link
Member

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.

@BoshiLee
Copy link

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)
}

@nbmarilag
Copy link

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!

@vovahost
Copy link

vovahost commented Dec 1, 2019

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}');

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.

@cytryn
Copy link

cytryn commented Dec 5, 2019

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}');

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

@vovahost
Copy link

vovahost commented Dec 5, 2019

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]

@munificent
Copy link
Member

@mit-mit C# enums are limited to any permutation or combination of the enumeration for a value. ie. hour & day & week or hour & day or day & week are all valid. If they're assigned ints, then it becomes obvious what's happening.

This issue thread is going in circles. We'll all make more progress here if we slow down, spend more time reading the previous comments, and more time editing down our own comments to be concise and build on what's been previously said. @JohnGalt1717, you have written 3,039 words in the past five hours. I know you aren't editing them carefully to make it as easy as possible for everyone else to read them because I can see an increased number of typos. Slow down. The language is not designed by filibuster and you are not persuading anyone by exhausting them.

To your specific points, please see my comment here. C# does not limit enum values to any combination or permutation of its defined values:

[Flags] enum SuitsFlags { Spades = 1, Clubs = 2, Diamonds = 4, Hearts = 8 }

var flags = (SuitsFlags)42;
System.Console.WriteLine(flags);

C# enum values have always been inferior to Java enums when it comes to safety. The language provides no guarantee that a value of some enum type is actually any of its named values or a bitwise combination of them.

They're stored as ints (32 bits used as flags) because it's vastly more efficient.

Dart enums are passed around by pointer like any other reference type. A variable holding an enum takes 64 bits on a 64-bit machine. If you have empirical evidence that that is vastly less efficient, I would like to see the actual data. I can't recall ever hearing anyone from the Java or Dart ecosystems indicate that enum representation was a measurable performance problem in their app.

It is extremely unlikely that we could move Dart to an unboxed representation for enums even if we wanted to (which, so far, I believe no one has been convinced of). It is fundamental to Dart's object model that every type is a subtype of Object. Consider:

enum Color { red, green, blue }
enum Suit { clubs, diamonds, hearts, spades}

main() {
  List<Object> things = [Color.red, Suit.clubs];
  print(things);
}

This program prints "[Color.red, Suit.clubs]". In order to do that, the value stored in the List<Object> for each enum must be something that knows that it is an enum and can call its polymorphic toString() method on it. We can't simply stuff a bare uint32 in there without losing that information.

Also, as you can see, we can't rely on the static type system to statically dispatch to each enum's toString() method because that information was lost when we stored it in a List<Object>.

C# does not have a unified object model. Each enum class is not a subtype of object. Instead, there is an implicit boxing operation when you pass an enum somewhere an object is expected. Boxing is user visible and affects the language in many corners.

For example, this is not allowed in C#:

class A {
  public virtual object Method() { return null; }
}

class B : A {
  public override Color Method() { return Color.Red; }
}

If enums were subtypes of object, then this would be a valid covariant return type, but it's not because enums aren't objects.

Dart does not have to auto-box because enums are true subtypes. But the implication of that is that their in memory representation must be compatible with Object, which is why they are generally passed around as pointers, like other reference types.

I don't really care one way or another if enums also get functions in them.

I would like to remind you and anyone else on the thread that the issue here is about methods on enums not enum representation. If you don't have an opinion on that, please don't comment here. It just clutters up the issue. File another issue about enum representation and we'll discuss it there.

@jodinathan
Copy link

I've made a simple test with classes, a random number and bit flags:

import 'dart:html';
import 'dart:math';

class Foo {
  final int bit;

  const Foo(this.bit);
}

extension Ff on Foo {
  bool isSet(Foo flag) {
    return (bit & flag.bit) == flag.bit;
  }
}

void main() {
  final rnd = Random();
  final bit = rnd.nextInt(1);
  final foo = Foo(bit | 2 | 8);

  querySelector('#output').text = 'FooHasBFlag: ${foo.isSet(Foo(1))}, FooHasDFlag: ${foo.isSet(Foo(8))}';
}

Dart2JS transpiles all main() to:

var t=C.m.p(1)|2|8
document.querySelector("#output").textContent="FooHasBFlag: "+((t&1)===1)+", FooHasDFlag: "+((t&8)===8)

You can see that Foo doesn't exist at all, everything is inlined and optimized.
So I really think that an enum with members, that has nothing but an int as property, can be used as a simple int.

@lrhn
Copy link
Member

lrhn commented Sep 29, 2021

@jodinathan (and everybody else)
Yes, an "enum" which is just a set of values (let's call it a "value enum") of another type (possibly int) can be very efficient at manipulating those values directly. And then there are other things it's worse at than class based enums. It's a different feature.

Dart does not currently have value enums. It could, but it doesn't. Issue #50 is a request for such a feature.

Value enums is also not what the current issue is about. It's about extending the enum feature that Dart already has.

We're not going to remove the current enum feature. We are likely going to extend it to make it more useful for those things that value based enums are already worse at. This issue is for discussing those extensions. If you are discussing something else, you are in the wrong place.

Discussing value enums here is not helping. It won't bring you any closer to getting value-based enums. That's what issue #50 is for.

@eernstg
Copy link
Member

eernstg commented Sep 29, 2021

[This comment was intended to support the notion that this is not the right issue to take a big discussion about enumerations considered as "numbers that are treated as bit sets". It illustrated that the [Flags] C# enumerations can be expressed in Dart-extended-with-views, which is a considerably better fit for that task than enum types in Dart. The contents of this comment is now in #50, here.]

@JohnGalt1717
Copy link

@munificent Yes you can hard override enums and put invalid values into the bit mask in C#. But unless you explicitly tell the compiler you want to do something stupid, it won't let you. Dart can easily be more strict and prevent even that if you wanted.

Do a simple bitshift 1 million times on Java's enums and compare it to C#. It's 7x slower as are all bitwise operators.

As for your claim that Dart can do things with enums that C# can't, your example is both contrived and a good example of things you shouldn't be doing in code, and if you absolutely must, you can do so in C# by using the new keyword which doesn't exist in Dart, and create a new method on the child class and you can still call into the parent class with base to the original implementation. Thus that still isn't an example of something you can't do in C# that you can do in Dart with Enums.

As for C#'s boxing and unboxing, unlike VB.net, in C# it's required to be explicit. In Dart, you're incurring the penalty by accident and the vast majority of developers aren't even aware of what they're doing, and it's this very behavior that creates an entire class of bugs in Dart with Generics that aren't required to be defined, or inferred and will default to dynamic without compilation error which shouldn't be possible and breaks a ton of stuff if a junior developer forgets to define the types on the generic they're using.

(and this is all relevant to this topic, because virtually all of the use cases for methods on enums go away if you can assign values and assign |ed values to other items in the enumeration.)

At any rate, I hack around the root mess of enums in dart, and since every single case here can easily be done with extension methods, and enums aren't in any critical path for me and likely won't be since Dart doesn't do server well, it's really immaterial to me and since this has turned into a religious debate instead of a functional one, I'm out.

@JohnGalt1717
Copy link

PS: Here's a good explainer for what I was saying about Java/Kotlin enums versus C# enums which are int based value types instead of object types on the stack.

https://betterprogramming.pub/android-how-enums-can-impact-the-performance-f787ef5903dd

They literally give a stand on your head approach to fix exactly what I'm referencing. It's always faster to work on the int (bits) than it is on an object.

In #50 I give a solution (which is the same as C#'s solution) to the request for Members on this topic. It solves the request, and doesn't introduce even more overhead to Dart's enums. It's the bottom half of the comment/suggestion if you don't care about the rest.

This could be added to the language as a abstract class with some special base functionality and then the generics functionality could be extended to allow direct definition of the enum in the generic definition which would then hide the underlying enum for which the class is based.

I.e.:

class EnumClassThingy extends Enumeration<TEnumType> {
   ... whatever you want classy style here.
}

Where TEnumType is restricted to the new Enum generic type restriction. (TEnumType extends Enum)

And if you really wanted to be fancy, you could allow the enumeration to be defined inline:

class EnumClassThingy extends Enumeration<{one = 1, two = 2, four = 4}> { ... }

This doesn't pollute enums, and allows developers to get all of the functionality of java (methods on enums) by choosing to get that functionality ON TOP of enum functionality, because Enumeration's generic type would extend Enum and thus allow Enumeration to have all of the root functionality that Enums have.

Of course, it's a class so it's allocated on the stack, but that's fine if you want this type of functionality. And then enums can still be value types (even if they inherit from object) if the rest of my suggestion there is taken, and thus be vastly faster as a result so you get the best of both worlds.

You could do this as of Dart 2.14 yourself by creating the abstract class:

abstract class Enumeration<TValue extends Enum> {
  final TValue enumValue;
  Enumeration(this.enumValue) {}

  List<TValue> get values;

  @override
  bool operator ==(Object other) {
    if (other is TValue) return this.enumValue == other;

    return (identical(this, other));
  }

  int get index => enumValue.index;

  @override
  int get hashCode => enumValue.hashCode;
}

Which you'd then implement like this:

class AuthTypeEnumeration extends Enumeration<AuthTypes> {
  AuthTypeEnumeration(AuthTypes type) : super(type);

  @override
  List<AuthTypes> get values => AuthTypes.values;
 
 
   ... Fancy functions etc. here.
}

You can of course add whatever other constructors you want, assign a new value to the enumeration, do equality comparisons, add methods, the whole deal. Of course if this was built into the language instead, then the Dart team could have it automatically do the values get method (if you care) and the assignment should be able to be done with just = instead of "assign" as you're able to do with C# because of explicit operator overrides.

I.e. the Dart team can give syntactic sugar pretty easily for this special case, but by adding 2 features to Dart itself, then this can just be an included class that uses explicit functionality. i.e. give us explicit operator overriding that allows us to explicitly define = as an example so that we can do casting explicitly from one object type to another in code like C# does, and figure out how to define Enumeration so that the value property can be retrieved without mirrors so that the values get method can be easily created in the class without hackery or having to override it.

i.e. if Dart did:

class SomethingEnumeration extends Enumeration {
static Something operator = (EnumType value) => Something(value);
}

Then we could do explicit casting at our class level this would make using Enumeration seamless in code to drop in replace a standard enum whereever we needed to add all of that function goodness.

As for Values, it would be nice if there was a way to get the actual enum from the Enum class which would then make that all automatic too.

@lukepighetti
Copy link
Author

Personally I find the current proposal confusing and I'm not a huge fan of it, but my opinion is only one of many

@alexeyinkin
Copy link

The current proposal still lacks one sugar @venkatd mentioned to get the enum object from its string representation:

T enumFromString<T>(Iterable<T> values, String value) {
  return values.firstWhere((type) => type.toString().split('.').last == value, orElse: () => null);
}

Such a use case is so common that even the proposal itself has an example of what one would with such enums:

static MyEnum byFieldValue(String value) => values.firstWhere((e) => e._field == value);

Can we possibly add from sugar method? It would take whatever arguments the constructor takes. Given the example from the proposal, it would be generated as something like:

static MyEnum<dynamic>? from(String _field, dynamic value) {
  // Here go generated comparisons.
  if (_field == "a" && value == 1) return foo;
  if (_field == "b" && value == 0) return bar;
  if (_field == "c" && value == 2.5) return baz;
  return null;
}

@mraleph
Copy link
Member

mraleph commented Nov 19, 2021

@alexeyinkin you don't need enumFromString since 2.15 which added a bunch of helpers to work with enums. Try this:

enum MyEnum {
  one, two, three
}

void main() {
  print(MyEnum.one.name == 'one');  // => true
  print(MyEnum.values.byName('two') == MyEnum.two);  // => true
  final map = MyEnum.values.asNameMap(); 
  print(map['three'] == MyEnum.three);  // => true
}

UPDATE: Initially stated that this was released in 2.14 which is incorrect, this is part of 2.15.

@alexeyinkin
Copy link

@mraleph is it really released? DartPad with 2.14.4 breaks on this code highlighting name, byName, and asNameMap. Also the latter two are not found anywhere in the docs nor in issues.

@mraleph
Copy link
Member

mraleph commented Nov 19, 2021

@alexeyinkin you are right, it's part of 2.15 not 2.14 release, I misread the CHANGELOG.

@jodinathan
Copy link

@mraleph is it really released? DartPad with 2.14.4 breaks on this code highlighting name, byName, and asNameMap. Also the latter two are not found anywhere in the docs nor in issues.

I just tested it in 2.15-edge and it worked flawlessly.
Very nice addition!

@igotfr
Copy link

igotfr commented Dec 2, 2021

related to #2006

@eernstg
Copy link
Member

eernstg commented Mar 4, 2022

This feature will be part of the next release of Dart, cf. dart-lang/sdk#47849. 🎉

@eernstg eernstg closed this as completed Mar 4, 2022
@leafpetersen
Copy link
Member

This feature is now turned on by default at HEAD, and will be available without a flag in the upcoming beta. Work on downstream tooling support is still in progress.

@VKBobyr
Copy link

VKBobyr commented Oct 2, 2022

I'm glad the Dart team made enums more powerful, but I think there was a missed opportunity to make enums more useful for app state management by allowing each state to have unique instance variables.

Here's an example:

enum HomeScreenState {
  // empty state with no instance variables
  case initial

  // states with instance variables that relate to the state
  case loading({double progress})
  case loaded({UserProfile profile, List<Document> documents})

  // state with instance variables and functions
  case error({Error error}) {
    void displayError(BuildContext context) {
      // ...
    }
  }
}

This is how Swift does it (without the functions part), and I found it extremely useful!

PS. Even though my example was geared towards app development -- I can see this being useful in stateful system.

@munificent
Copy link
Member

Dart enums are about defining a closed set of values known at compile times. Swift enums are more like algebraic datatypes in other languages where you are defining a fixed set of type cases but you may have arbitrary values stored in them and created at runtime. For the latter use case (similar to Kotlin, Scala, et al), we're working on adding sealed types and pattern matching.

I think modeling algebraic datatypes using subtypes yields a more powerful expressive feature than Swift's relatively restricted enums (though I do like how terse Swift is when declaring them).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Proposed language feature that solves one or more problems request Requests to resolve a particular developer problem
Projects
Status: Done
Development

No branches or pull requests