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

Reply via email to