I guess ultimately it depends on which language you are more familiar with...
I guess ultimately it depends on which language you are more familiar with...
type Message
= IncrementBy Int
| DecrementBy Int
| Set IntIn Dart, if you do:
sealed class Message {}
class IncrementBy extends Message {
final int amount;
IncrementBy(this.amount);
}
class DecrementBy extends Message {
final int amount;
DecrementBy(this.amount);
}
class Set extends Message {
final int amount;
Set(this.amount);
}
You can then write functions that accept specific cases, like: onlyOnIncrement(IncrementBy increment) {
...
}
In Elm and friends, IncrementBy is just a type constructor, not a type. Further, we can use the class hierarchy to reuse shared state and behavior in a way that sum types don't let you easily do. In your example, each case has an int and it so happens that they reasonably represent roughly the same thing, so you could do: sealed class Message {
final int amount;
Message(this.amount);
}
class IncrementBy extends Message {
IncrementBy(super.amount);
}
class DecrementBy extends Message {
DecrementBy(super.amount);
}
class Set extends Message {
Set(super.amount);
}
And now you can write code that works with the amount of any Message without having to pattern match on all of the cases to extract it: showAmount(Message message) {
print(message.amount);
}
So, yes, it's more verbose than a sum type (and we do have ideas to trim it down some), but you also get a lot more flexibility in return.It's only more verbose for the code that is defining new types. Code that is simply defining behavior (either in functions or methods) is unaffected and my experience is that that's the majority of code.
In practice, most real-world Dart code that uses sealed types also defines methods in those types, getters, and all sorts of useful stuff. Once you factor that in, the data definitions themselves are a relatively small part.
(Of course, you could argue that defining class hierarchies is already intrinscally bad. But Dart is an object-oriented language targeting people that like organizing their code using classes.)
type Message
= IncrementBy Amount
| DecrementBy Amount
| Set Amount
type Amount = Amount Int
Obviously this is a contrived example - you wouldn't bother if you were dealing with an Int but once the message gets more complicated it can make sense.Given the above ADT, how would you write a function that prints the amount of a Message, regardless of which case it is?
Of course, you can also reorganize you datatype so that the shared state is hoisted out into a record that also contains a sum typed field for the non-shared stuff. But that reorganization is a breaking change to any consumers of the type.
Modeling this on top of classes and subtyping lets you make those changes without touching the user-visible API.