Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119768 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 47539 invoked from network); 29 Mar 2023 12:30:21 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 29 Mar 2023 12:30:21 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 51DDC1804F8 for ; Wed, 29 Mar 2023 05:30:19 -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,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL,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-pj1-f53.google.com (mail-pj1-f53.google.com [209.85.216.53]) (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 05:30:18 -0700 (PDT) Received: by mail-pj1-f53.google.com with SMTP id d13so13922018pjh.0 for ; Wed, 29 Mar 2023 05:30:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; t=1680093017; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=iZX7A+xpqCe0FPe2eChCNrx+ClV30uFBuBQKGfkRAak=; b=qEUb1F8LfoCAlqpa4UWFtBMX1xxYa2Lr/zP0oTbeJrWD/yVUocp0VnvhqcDr6NJbH0 bMYTJMytXXIx/i+scT4OqsG+8JYVHwa4TFlbxAgUr/yPZlGqGH+ufMrn03vrhkFhPkcS YI3K0KjVTjtwqQl9Re2tLJvVaXuMui7T7L7AsOnizw+gKjSp+0J0njKr/nS0MTg+dfwY 4FCbwGcIUwOvNH7fPmLudNr+kcVo1EKlK/OBoy5KP1kZ1a8z+H8Dt3OGHVL+lDvycYB7 kIFzR70SvUiBGTuZAlmaOzDdwu83MuplKMlkYL7fWjDaCVGKSo7OGSL4Z36OHiADdCBt j07w== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; t=1680093017; h=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=iZX7A+xpqCe0FPe2eChCNrx+ClV30uFBuBQKGfkRAak=; b=1jfHD60uu1R/QadaUMpjEXNJvsDNNkbk61VzYt4bH0P/55r1yRZPwpRtA/8oz/ltCr atECRDQwg3u9E+xEI6H9d8nvDFXf6rQYFL23dpwnKBeJJzYexhvl4pv/wqfqYlSKMO8s Ek9eFA4HyEpDiM9A4XU6yNQz67hFJuukaqrjHjlbtJLRAAS1OYIKst1lPRQhvg7p3Xpu 7KBbVZBm3HPg3trgFH0KkB6I1PL9tIwGXITr8Mgent/x8A+/ec1Lg3Nu1dbYEz1KwU2v YzZlbSlIIJAKT1qvvhWCAYgE9sB/OFmRdeoblICMPI6jhg8WidL8CFGEHIJ2rUQ31iG0 VfwA== X-Gm-Message-State: AAQBX9cd5v0RKXOU7x24IxSsiiYKHddWEx5jA4FqdRHgIVe3XIOYZ+oY lILFYifABROfl+UGZvGLr3Asb63FLtAfT1o1ZbA= X-Google-Smtp-Source: AKy350bewLGMV9jSzRda7WzMcymrtAs6ndkdZQql2ylRt0Y/fERFBPcXs744h79M3ti9OsUWnBSAkqPlh1fYXYDwoig= X-Received: by 2002:a17:902:ce81:b0:1a1:c945:4b2c with SMTP id f1-20020a170902ce8100b001a1c9454b2cmr7787078plg.7.1680093017107; Wed, 29 Mar 2023 05:30:17 -0700 (PDT) MIME-Version: 1.0 References: In-Reply-To: Date: Wed, 29 Mar 2023 13:30:06 +0100 Message-ID: To: =?UTF-8?Q?Rokas_=C5=A0leinius?= Cc: internals@lists.php.net Content-Type: multipart/alternative; boundary="00000000000079748d05f809233b" Subject: Re: [PHP-DEV] [IDEA] allow extending enum From: george.banyard@gmail.com ("G. P. B.") --00000000000079748d05f809233b Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Wed, 29 Mar 2023 at 09:31, Rokas =C5=A0leinius wrote= : > 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 extend > 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 use 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 file 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 something returns a GenericErrors well who knows if you cover all cases because someone might have ad-hock added a new one. PHP's type system is not perfect yet, but it has become powerful enough that 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 an "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 --00000000000079748d05f809233b--