Hacker News new | past | comments | ask | show | jobs | submit login

Flutter 3 comes with an upgrade to Dart 2.17 [1], which has quite a few improvements as well... including state on enums.

While that's great, I was hoping it would be like in Rust, where each enum variant can declare its own state components, but unfortunately it seems to be more like Java: same state for all variants.

Well, at least there's quite a few other small but useful improvements... and they showed how they really listen to the community by implementing the new syntax for passing on constructor parameters to a super-class... and by improving the docs of the 200 most popular packages with lots of examples, as requested by the people.

I like how they're listening to the community as well to implement meta-programming (like macros) [2] to solve the main pain point, currently, in Dart, which is how verbose it is to generate code for things like serialization and data types.

Once they get that, Dart will be a really good language to work on (it's already quite ok IMO, despite most people, usually those who don't actually use it much, hating on it).

[1] https://medium.com/dartlang/dart-2-17-b216bfc80c5d

[2] https://github.com/dart-lang/language/issues/1482




> While that's great, I was hoping it would be like in Rust, where each enum variant can declare its own state components, but unfortunately it seems to be more like Java: same state for all variants.

Yes, the enhanced enums we shipped in 2.17 are like Java enums.

We are also working on support for pattern matching and algebraic datatype-style programming: https://github.com/dart-lang/language/blob/master/working/05...

I say "style" here because object-oriented languages like Dart can already mostly model sum types using subclasses. What you need to get the rest of the way there is basically just:

1. Sealed types so that the compiler can check for exhaustiveness when you match over all of the subclasses.

2. A nice pattern matching syntax to let you discriminate between the subclasses and destructure them.

3. Ideally, a nice lightweight syntax for defining a sum type family as a superclass and set of subclasses, though this is relatively less critical.

We're hard at work on this, but pattern matching in general is a pretty large feature and retrofitting it into a language whose syntax wasn't initially designed around it is a challenge.

I'm very excited about macros too. That's another large, difficult feature, but one that I hope will provide a lot of power to users and make the entire ecosystem more valuable over time.


Any thoughts on the freezed package [0]? That's what I use currently for ADTs and exhaustive pattern matching on them, would be cool to see similar syntax in the official implementation.

[0] https://pub.dev/packages/freezed


It won't be that exact syntax, but, yes, the goal is to offer that kind of functionality but integrated more into the language.


That feels like quite an awkward way to squash tagged unions into a class structure... But maybe it will work. I would say special syntax for it probably is critical because defining an entire class for each variant does not sound like fun!


> That feels like quite an awkward way to squash tagged unions into a class structure... But maybe it will work.

It's what Scala and Kotlin do and I think it's a fairly natural mapping. (Swift takes a different approach with their enums).

> defining an entire class for each variant does not sound like fun!

If you come at it expecting the brevity of ML, yes, it's not. But if you accept that those variants are real classes and may also have their instance methods, documentation comments on the fields, etc. then the overhead starts to feel less onerous.


> While that's great, I was hoping it would be like in Rust, where each enum variant can declare its own state components, but unfortunately it seems to be more like Java: same state for all variants.

As much as I like Rust’s enums, I think they messed up on the naming. Java (and according to your comment, Dart) gets enum rights. What Rust has under this name is sum types, which is a separate (more expressive) concept and the two only correspond with each other in the case of a sum type where each component is of a zero-arity type.


There is no real reason to have basic enums if you have ADTs , since those can easily provide everything a plain enum gives you.

I guess the name was just a historical artifact.


I agree (that’s what I meant under the more expressive part), though it is a bit more complex with identity in the way. Java’s enums are also the singleton pattern.

Java recently got ADTs as well in the form of sealed classes and records, here an enum would look like this:

  sealed interface Color permits Red, Blue, Green {
}

  record Red() {}
  record Blue() {}
  record Green() {}

You can now create as many Red instance as you want, they will be “equals” only under equals(), not under ==, while the latter is also true for the enum case.


The interface implementation types may include enums, though not sure that would help much in your example.


no the feature you're looking for is sealed classes, see e.g. Kotlin. Rust enum variants cannot be externally defined classes


That's completely orthogonal to ADT vs enum.


Enums enable two things: check current type from union of types and exhaustivity check in switch

The former is solved by reflection, the latter by sealed classes.


I disagree. "Sum" and "product" types are really really unclear names that only make sense if you've studied some advanced CS and even then they're bad names - not descriptive at all.

Enum is much better - you just enumerate all the values the type can be (plus optional associated data).


Perhaps, though given that it is already used slightly differently in a very well-known language can also cause hiccups.

For the record, algebraic data types get there names from the fact that the “number” of instances that are under a given type gets added or multiplied together. Let’s say we have a ColorChannel “enum” of R, G, B. That is there are 3 instances ever under this ColorChannel type. Let’s create (with some syntactic sugar) an 8bit unsigned int which has exactly 256 possible instances.

Now create a Pair (ColorChannel, u8) type. This will be a product type, since the number of possible constituents is 3x256.

Let’s look at the often used Option type, which wraps another type. This looks something like enum Option<T> { Some(T), None }

We have two possible types here, but one can contain T possible types. So Some(T) is basically a product type of 1 other type, resulting in it holding that type’s cardinality, while None has a single instance — the Optional sum type thus has card(T)+1 possible instances.


Rust isn't alone though - Swift's `enum`s are essentially the same as Rust's enums.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: