Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119784 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 30616 invoked from network); 30 Mar 2023 07:36:29 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 30 Mar 2023 07:36:29 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3BB0B1804D4 for ; Thu, 30 Mar 2023 00:36:29 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-ua1-f51.google.com (mail-ua1-f51.google.com [209.85.222.51]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 30 Mar 2023 00:36:28 -0700 (PDT) Received: by mail-ua1-f51.google.com with SMTP id x33so13145855uaf.12 for ; Thu, 30 Mar 2023 00:36:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1680161788; x=1682753788; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=S+u2Cd4spFP8ZNmlrseuc+jl7ZU6D3mOe78fS/ajbLA=; b=MRJK+8vKAoDluClyYs85XHRlEzgKonzIxz7Zx2wZu1x6jHfMyIFyJDI4NrBgNbAEpu /Yjilr4WyjuF7FZ1MsH0b2J1LZJAbhGSL1XBXZadr2mM4FMq1MCLx4bmRkYGeg3zDvxr Xemh9SOVPMdly2KK8tB+BIQz5Y1XLzcjLSts4p4QOgep6/Re8w9nZlB4144NGtS71j3Z Cw0geQ63QVFhFelPUmP9W2ZoS5BqyxKyBd7zJLCPBTD/pz+qsMNeFL6nollIKMVm94a2 AQDjA/dB9+O79CiipJWsxcKMIkPrKsc+HqtRrtO1h0wggGJgpyOeKLRMcKxE/NzvEjEV OMAg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680161788; x=1682753788; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=S+u2Cd4spFP8ZNmlrseuc+jl7ZU6D3mOe78fS/ajbLA=; b=Kok4rgQd9E9eJYlc7egynCNeo3P5FywtMSskioxYgGh39p+IbtyMol3NeopV12RMQc arReVdj6MBWOyuejHKEnE9ER9GxadaTSd2mCbTifj3uqZAiTdvZVT9pueDeYmGUpE3vI 6Xcru0+y++KzUDOzFZ2qXAO848eohxx+VCbD8DR+IaSkq6iX7gs0+OSUSBcOoaJ1G6bk m28djk6qSW6FUWVf9MOaqkSEzvuvefjJdJzSwMCHI6G9qz3GrQP4HAtqBzFMQO7nKO5O EAAQTmGfJwSzfmlNflbntYkM3bfW2t6zfOSTXd7SWdontIvCou1Fu8jP3a+sVsxCdvqO mhJg== X-Gm-Message-State: AAQBX9fRzLHMFx3Tv3v5i5MysAPqBz93d1lwGh8YhTdvOVPzJC9/N+OJ hqVY8zMdCWWPYy/+XRn6vXIhCb49GuzLRKoHNNxA8SEqcME= X-Google-Smtp-Source: AKy350aK5mN+m0W3tPMuq2JMKoioXonWcuhmkjliFDUSrI1zgKtIw6TAS9s0uVvAyu4VOCYYOSxIzWqhchviFAoX5hI= X-Received: by 2002:a1f:9802:0:b0:43c:2acb:9a60 with SMTP id a2-20020a1f9802000000b0043c2acb9a60mr63314vke.3.1680161787927; Thu, 30 Mar 2023 00:36:27 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Thu, 30 Mar 2023 10:36:08 +0300 Message-ID: To: Larry Garfield Cc: php internals Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] [IDEA] allow extending enum From: rokas.sleinius@gmail.com (=?UTF-8?Q?Rokas_=C5=A0leinius?=) On Wed, 29 Mar 2023 at 18:40, Larry Garfield wrote= : > > On Wed, Mar 29, 2023, at 2:25 PM, Rokas =C5=A0leinius 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 =3D 'You screwed up'; > case OurFault =3D '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, co= mmon 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 som= ething 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 reason= s 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 w= ell? Do interface definitions carry over? I don't know. > > B) The long-term goal is to expand Enums to include associated values (ht= tps://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 anothe= r 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 =3D 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!!