Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119770 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 52330 invoked from network); 29 Mar 2023 13:22:36 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 29 Mar 2023 13:22:36 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 5463E180211 for ; Wed, 29 Mar 2023 06:22:35 -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-vs1-f43.google.com (mail-vs1-f43.google.com [209.85.217.43]) (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 ; Wed, 29 Mar 2023 06:22:34 -0700 (PDT) Received: by mail-vs1-f43.google.com with SMTP id z17so6661407vsf.4 for ; Wed, 29 Mar 2023 06:22:34 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1680096154; x=1682688154; 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=9S5goMLB/u/QHbwH6SJbWNKnU4PbI5dAGreV+6nYpUA=; b=p0LaquWk8tVGwUxF15nRq+Ul0nolw7490le1k7OTSjra7wz8X/rLv5QDXq+4MUTrFM Ezt/yOyiuwnU0hHyPsDOMcVkN09edUo9XLreNyYpBX8uSqMrorG8vkM8P45/hEWi/GNf QvRo+hDejt0jyvfhnC4gz3ViCBnZSv+WgT14BQ95pDjfjed/rWXKk9If8GY+2e0QvF6P yWjwG+nJlKjTanG25m3+CyXm2xWseI07EJSf8V0+TrVnKskXBwr517PkLIw+lvwCaG0T wy/LQ2jlLGPDISRrFS/m6PYCG5mtAA3GMKF2rEFVbDdIRIxgTxwllp5Etv9/36yW0AbW mo6g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680096154; x=1682688154; 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=9S5goMLB/u/QHbwH6SJbWNKnU4PbI5dAGreV+6nYpUA=; b=pXt+sZSqnIZH9egmDYkDeyUQjWZBiWhVj8yO6MuRpvT7HqXBMYKQwk2agAOBwGGBHJ 3HSg8uB1JYw8kjlTBmb01A/7fwRYZrXgxP9kyXK54tqMlZvMVMiymQMXNLMC/Bw2O8Pa l3FluvhNUAv5A/IkNcKY12Fufhze6nRx1q0EM/aTI+WoaeWVZY4qMeynQCLJELSSliUx W9G2kpPnIFSJ2fGDFZTt6MVH4ETzRDbwSSakyAiCyE/2cm8qqwK8BSHLPiPKlnlCs3zH D6LI8nqj4HQjCfzM6wrwyKzf/Wu90n56PDzpK82kOpKRr8eGx/4WdhHzxLm35ILsT9yC oZ7Q== X-Gm-Message-State: AAQBX9fUarFhLDsj+HE3MkSR03hheKx/GkzXmbvSUsPDrkgVse0+ZWuL MPkO+lCkfn0IkRPmM5LlkRzT4fICWnDizkz7NHc= X-Google-Smtp-Source: AKy350bd048VsAW8nW7DHhsq5GkCAGjE3Jh+4+6Ij1l3UGz8jM7N5V0swIWmNRKH7gOS3HiK7af/k5xGdRA1npzRvsw= X-Received: by 2002:a67:ca16:0:b0:421:eabb:cd6a with SMTP id z22-20020a67ca16000000b00421eabbcd6amr10625788vsk.7.1680096153976; Wed, 29 Mar 2023 06:22:33 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Wed, 29 Mar 2023 16:22:16 +0300 Message-ID: To: "G. P. B." Cc: internals@lists.php.net Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Subject: Re: [PHP-DEV] [IDEA] allow extending enum From: raveren@gmail.com (=?UTF-8?Q?Rokas_=C5=A0leinius?=) Ok so I am trying to find the argumentation here: >This is by design. >The point of enums is to be limiting. This is clearly an assumption. That statement is not in the docs or RFC, nor such an oversimplification makes logical sense to me, but maybe you have a source to back it up..? >Re: problem in the OP >You are approaching the design of this in a fundamentally wrong way. The described problem is dealing with error *codes* not *types*, which means that each error is assigned a new *code*. We are dealing with anticipated errors here, things like validation, data integrity, 3rd party API breakage etc. e.g.: user gets code 456 trying to ship out package, it says package not paid, user says he looked it up, its paid. The developer has a very concrete lead to the problem - lookup usages of `ErrorCodes::Code_456`. The set in question is *finite*, as you say of course, but much larger and different in principle than in the solution you are proposing. Problem in OP is looking for a way for end users to keep adding new domains to the error codes passed to the parent system to be handled. The actual, real requirements are: 1. Ease of management of codes: simplicity of adding *new* codes to the set, easy lookup, simplicity of making sure a code is not used elsewhere before using it. All perfectly fulfilled by enums. 2. Reusing the parent system for different modules, using the parent system in two different packages I want to opensource. Open Sourcing the parent system.. Rowan Tommins is right on the target however, that is amazing feedback for the desired functionality, excellent distillment of logic and all correct points! I will take some time to think about that. On Wed, 29 Mar 2023 at 15:30, G. P. B. wrote: > > On Wed, 29 Mar 2023 at 09:31, Rokas =C5=A0leinius wro= te: >> >> Enums were a very useful addition to PHP, however one aspect of them is = neither >> explicitly documented - or seemingly even talked about. >> >> Enums were implemented as final so they cannot be extended nor can exten= d >> anything else. > > > This is by design. > Enumerations are in type theory parlance sum types. > Objects in PHP, in general, are what are called product types. > >> >> From a user perspective it's surprising - and actually limiting. > > > The point of enums is to be limiting. > >> >> USAGE EXAMPLE: >> I am making an error management system: each error presented to the user >> must have a unique code visible. >> >> ```php >> class SystemError >> { >> public function __construct( >> private string $errorText, >> private ErrorCode $code >> ) { >> } >> >> public function __toString(): >> { >> return $this->errorText . ' ' . $this->code->toString(); >> } >> } >> // ... >> >> enum ErrorCode >> { >> case Code_1; >> case Code_2; >> >> public function toString(): string >> { >> return 'Error code:' . substr($this->name, strlen('Code_')); >> } >> } >> ``` >> >> Now I want to modify it to support different modules with different >> namespaces for >> errors, e.g. an ApiError, simple enough: >> >> ```php >> enum BaseErrorCode >> { >> // ... >> } >> >> enum ErrorCode extends BaseErrorCode >> { >> case Code_1; >> case Code_2; >> >> // ... >> } >> >> enum ApiErrorCode extends BaseErrorCode { >> // ... >> function toString(): string >> { >> return 'Error code:API-' . substr($this->name, strlen('Code_')); >> } >> } >> ``` >> >> This results in a syntax error. > > > You are approaching the design of this in a fundamentally wrong way. > Enums, as sum types, are meant to enclose a *finite* number of states. > If you want to expand those finite number of states, the solution is to u= se a union type. > > Let's say you have those 3 enums: > > enum GenericErrors { > case ErrorType1; > case ErrorType2; > } > > enum FileErrors { > case FileErrorType1; > case FileErrorType2; > case FileErrorType3; > } > > enum NetworkErrors { > case NetworkErrorType1; > case NetworkErrorType2; > case NetworkErrorType3; > } > > And you have a function that can fail with either a generic error or a fi= le error then you can be explicit by having: > > function foo(): T|GenericErrors|FileErrors { /* Do something or Fail */ } > > This signature provides you with great type safety and can be checked via= static analysis that *all* error cases are handled. > Moreover, you know you don't need to handle NetworkErrors. > Extending an Enum *loses* you this type safety, because now ff you say so= mething returns a GenericErrors well who knows if you cover all cases becau= se someone might have ad-hock added a new one. > > PHP's type system is not perfect yet, but it has become powerful enough t= hat you can do things like what I just described. > Ideally we would have generics, and you could use a Result/Either Monad (= fancy word for "wrapper") to have a return type of Result > > Use the type system properly instead of trying to shove everything into a= n "Inheritance" view of things. > Union types are not "bad", they are another way of creating a sum type. > (You could, with a lot of effort, create "proper" enumerations since PHP = 8.0 by using union types and singleton classes.) > > >> PROPOSAL: >> >> Enums should be able to extend other enums. >> >> For a complete wishlist, add: >> * abstract enums; >> >> * enums allowed to implement interfaces; > > > Enums can already implement interfaces: https://3v4l.org/tKtQ0 > >> >> However since I have no experience in PHP source code, I can only >> provide the test suite for a possible PR this might have :( >> >> Do you think this is likely to get implemented? > > > I dear hope so not. > Breaking fundamental type theoretical assumptions is terrible. > > Best regards, > > George P. Banyard