On Wed, 29 Mar 2023 at 18:40, Larry Garfield <la...@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: > > 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!! -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php