Hi Larry and Ilja It's great to see you're looking into enums, thanks! I have a few considerations from a userland point of view. I've been maintaining a userland enum implementation for a while now [1] so I think I share a thing or two about my experience.
- Scalar enums are spot on, exactly what I'd expect. - Support with match is awesome, and I think makes it so that array key support isn't necessary. - Others already addressed that serialization and deserialization would be a nice feature. A common use case is to store enums in a datastore of some kind, and it would be nice not having to make dedicated factories for them. - The `case` syntax feels quirky. I assume it's because PHP wouldn't allow something like this: ``` enum Suit: string { Hearts = 'H'; Diamonds = 'D'; Clubs = 'C'; Spades = 'S'; } ``` Finally, I've got one (rather large) concern about object enums, specifically with methods implemented on a per-enum basis. I did the same [2] when I first implemented my userland package. From my research back then, I believe only Java [3] allowed this behaviour. If you've checked out that link, you've seen that value specific methods have been removed in v2. That's with good reason: they turned out to rather cumbersome to maintain and even a bit useless. Here's why: - You example shows one method, the `color` one, which is still kind of manageable. If you allow enum methods though, you'll often end up with more than one method: `label`, `color`, `index`, `name`, `id`, are a few that come to mind. In the end an enum grows very large and unmanageable, with often lots of repeated code. - Enum value methods actually are the state pattern [4] in disguise. One difference being that enums objects can't manage their own internal state, so they become less useful in applying the state pattern compared to using classes. I think enums shouldn't aim to solve the state pattern. It's out of scope for what enums should do and their way of solving the state pattern will be worse in practice compared to using classes. I'd say it would be good to keep the defintion of enums in mind: > "an enumerated type […] is a data type consisting of a set of named values > called elements, members, enumeral, or enumerators of the type. The > enumerator names are usually identifiers that behave as constants in the > language." [5] "Named values" and "constants" being the keywords here, there's no "behaviour" implemented by enum values, which is why only a small amount of languages allow this kind of functionality. I realise enum objects might seem like a good idea to provide more value-specific functionality in a concise way, but let's compare per-value methods with a method on the base enum: ``` enum Suit implements Colorful { case Hearts { public function color(): string { return "Red"; } } case Diamonds { public function color(): string { return "Red"; } } case Clubs { public function color(): string { return "Black"; } } case Spades { public function color(): string { return "Black"; } } public function shape(): string { return "Rectangle"; } } ``` vs ``` enum Suit implements Colorful { case Hearts; case Diamonds; case Clubs; case Spades; public function color(): string { return match ($this) { Suit::Hearts, Suite::Diamonds => "Red", Suit::Clubs, Suite::Spades => "Black", } } } ``` In summary: - If you'd use enum objects for "simple functionality", I'd say `match` will always be the more concise way. - If you'd use enum objects for handling complex state, you're better off using classes and properly implementing the state pattern. I don't think enum objects should be a blocker, if people _really_ want it then fine. Based on my experience though, I'm rather sure that they won't be very useful, and would love to hear your opinion on the matter. Kind regards Brent [1] https://github.com/spatie/enum [2] https://github.com/spatie/enum/tree/v1#enum-specific-methods [3] https://www.geeksforgeeks.org/enum-in-java/ [4] https://en.wikipedia.org/wiki/State_pattern [5] https://en.wikipedia.org/wiki/Enumerated_type > On 7 Dec 2020, at 10:30, Rowan Tommins <rowan.coll...@gmail.com> wrote: > > On 07/12/2020 01:00, Paul Crovella wrote: >> Instance state being global is a well-known problem with singletons. >> Maybe don't use singletons then. Or simply document them as was done >> in the RFC. I'd prefer the former since singletons don't seem to buy >> much here but problems, though maybe I'm missing something. > > > Yes, I think you are missing something - or maybe I am, because I honestly > can't picture what it would look like for enums *not* to be singletons. > > Would Suit::Hearts be a constructor, producing a new instance each time, each > with its own state? Would we then overload ===, so that Suit::Hearts === > Suit::Hearts was still true somehow? > > > > In any case why is static state being (kinda sorta) restricted along with > > it? > > > On the face of it, I agree, static properties could be supported. But looking > at the details of the current proposal, it might actually take some thought > to make them feel natural. As I understand it, each case acts like a > sub-class, which is useful for over-riding instance methods, but would mean a > static property would be defined separately on each case: > > enum Suit { > static $data; > case Hearts; > case Spades; > case Clubs; > case Diamonds; > } > > Suit::$data = 42; > $mySuit = Suit::Hearts; > var_dump($mySuit::$data); // will not print 42, because Suit::Hearts::$data > is a different property > > > As Pierre says, the idea of backing enums onto objects is mostly an > implementation detail; their fundamental design is based on how enums are > generally used, and implemented in other languages. > > Rather than "objects which are a bit enum-like", it might be useful to frame > them as "enums which are a bit object-like". The primary consistency needs to > be with what people will expect an enum to do. > > Backing them onto objects makes it easy to add on any object-like behaviour > that feels useful, but once we've added it, it's much harder to remove or > change if we realise it's causing problems for users, or getting in the way > of other features. > > That's why I was asking if you had use cases in mind, because I was starting > from that position: assume they have *no* features, and add the ones we think > are necessary and achievable. > > > Regards, > > -- > Rowan Tommins (né Collins) > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php