Re: [IDEA] allow extending enum
| From: | Rokas Å leinius | Date: | Thu, 30 Mar 2023 07:36:08 +0000 |
| Subject: | Re: [IDEA] allow extending enum | ||
| References: | 1 2 3 4 5 6 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-119784@lists.php.net to get a copy of this message | ||
On Wed, 29 Mar 2023 at 18:40, Larry Garfield <larry@garfieldtech.com> wrote:
>
> On Wed, Mar 29, 2023, at 2:25 PM, Rokas Å leinius wrote:
> > First, I'm pretty sure I agree now that enums should *not* be
> >
extend-ed as regular classes, there's a fundamental
> > difference as
> > you state - the extended enum is a fundamentally different THING as it
> > can hold different values - when an enum's sole purpose is to hold one
> > of the set of values.
> >
> > That is to say - for most implementations that's the desired case.
> >
> > I'll refer to the solution to the OP problem as ECS, Error Code System.
> >
> > For ECS, the most elegant, but also the only, solution I can come up
> > with - is the kind of enum that you also suggest, a
> > base-enum.
> > abstract enum?
> >
> > Let me try again to describe the problem that I came here with that is
> > unsolvable by union types:
> >
> > 1. ECS is a *generic* component. I want to plug it into any working
> > system (like an existing cms).
> > 2. Invoking it must provide a unique ErrorCode. The existing cms has
> > to create an enum that will be accepted as type:
> > ErrorCode. It
> > cannot edit the existing ErrorCode as it is part of ECS and not the
> > cms.
> > 3. There is NO special handling for the custom ErrorCode's that the
> > users of ECS create. We are just using the enums inferred value.
> >
> > I will keep processing this situation further, but for now it seems to me like
> >
> > 1. Extending enums is fundamentally flawed.
> > 2. Basing enums off of other enums has valid usage scenarios.
> >
> > In that case, and, again, this needs way more thought to it, it's not
> > such a "generic way forward" that seemed to me at first and might only
> > provide marginal value at the cost of type complexity and that is most
> > probably, unfortunately, not worth it...
> >
> > (unless abstract enum might make sense, but my brain needs
> > some time
> > off of this problem for now)
> >
> > Thank you for such a thought out discussion, everyone!
>
> 1) Please don't top-post.
>
> 2) Some good reading material for this topic, both on enums and on error handling:
>
> https://peakd.com/hive-168588/@crell/on-the-use-of-enums
> https://peakd.com/hive-168588/@crell/much-ado-about-null
>
> They're not short, but that's because they are complete. :-)
>
> 3) In the error code case, the answer is to leverage the fact that enums *do* support
> interfaces.
>
> interface ErrorCode
> {
> public function message(): string;
> }
>
> enum CommonErrors: string implements ErrorCode
> {
> case YourFault = 'You screwed up';
> case OurFault = 'We screwed up';
>
> public function message(): string
> {
> return $this->value;
> }
> }
>
> readonly class SomeoneElseError implements ErrorCode
> {
> public function __construct(privateUser $atFault) {}
>
> public function message(): string
> {
> return sprintf('%s screwed up', $this->atFault->name());
> }
> }
>
> Now an error handling system can type against the ErrorCode interface, common errors have
> trivially simple enum values you can use, but you can also make your own. In this case, you're
> *not* using an enum as a limited-set; you're taking advantage of it being a way to predefine
> singleton objects. I would consider this a completely valid use of enums, and actually do something
> very similar in my serialization library:
>
> úî™õþoσ¯
> ðÆÖhttps://github.com/Crell/Serde/blob/master/src/Renaming/RenamingStrategy.php
>
> https://github.com/Crell/Serde/blob/master/src/Renaming/Cases.php
>
> https://github.com/Crell/Serde/blob/master/src/Renaming/Prefix.php
>
> 4) As others have said, extending enums is a bad idea with lots of reasons it's a bad
> idea, both conceptual and pragmatic. However, I would be open to discussing a
> use for enums to import cases from one enum into another..
>
> There's two concerns with that to consider:
>
> A) What happens to methods on the imported enum? Are they pulled in as well? Do interface
> definitions carry over? I don't know.
>
> B) The long-term goal is to expand Enums to include associated values
> (https://wiki.php.net/rfc/tagged_unions, although that's a bit out of date now so don't
> take it as a roadmap). How would use-ing an enum within another
> enum affect that? I have no idea, off hand.
>
> --Larry Garfield
> 1) Please don't top-post.
Am I doing it right now? I've never been on a mailing list.
In fact, I was too young and missed out on BBS as well, and now using
this laughably archaic collaboration method, receiving mostly
stone-harsh replies generously sprinkled with genius insights, having
to quite literally hack a registration form as one of the several
required steps for contribution... Wow this is a really remarkable
experience for me :D
> 2) Some good reading material for this topic, both on enums and on error handling:
Thanks, noted, bookmarked, subscribed.
BTW the ECS example is only dealing with Errors because it's a concept
I thought people would grasp and relate to easily.
> yesssss, enums support interfaces!!!!!!
Less than five minutes away from the keyboard I realised that this is
the key and my problem is solved more elegantly than the initial idea
of extending - the interface is perfect, thank you to everyone who
pointed it out!
I am really impressed how elegant and actually genius the enum
implementation is. So well rounded, minimal, yet creates so much
value!
Re: Rowan:
> The concept of "uniqueness" only makes sense within a certain context
That's why in ECS example I added the toString() method to the enum,
but you're right, I should have named it something along the lines of
getErrorPrefix() - and now - using the interface approach I can
assure any enum passed to "AddError" will also provide a prefix along
with the enum->name (error code) + enum->value (error text) :)
> type ApiError = DatabaseError|HttpError;
Sounds cool and useful, hope there's motivation enough to see it
through, but that's a separate topic, I'm glad this discussion
happened, bye now everyone!!