Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:112452 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 23568 invoked from network); 7 Dec 2020 10:55:42 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 7 Dec 2020 10:55:42 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 777801804CA for ; Mon, 7 Dec 2020 02:24:35 -0800 (PST) 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,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-Virus: No X-Envelope-From: Received: from srv015.mail.ichtushosting.com (srv015.mail.ichtushosting.com [159.69.182.195]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 7 Dec 2020 02:24:34 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=stitcher.io ; s=default; h=Message-Id:In-Reply-To:To:References:Date:Subject:Mime-Version :Content-Transfer-Encoding:Content-Type:From:Sender:Reply-To:Cc:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=0HGO3sC9cwnaDAOe3NRrIGHxze1ouTedRPwPKmmrUMU=; b=tvw23z2oDg9JZdXVT3vk6Wathr MPHJsXsDZQ7iShPsueU6UElqYlagm2ZmThmw0p3YmCaxTeQ8xDiJUfXFMTqLBvQTOk8vMfRkomd/L vm6ImbjUbcY/MTN/lUifM5JsgLsKjNe0i+3LAfDyOIaWHFjGNo6AcU9igKgpCFhFW4OmSP76EYTbW MzlMLz55QnKbZdA8LrwIMa9q5gWfwW0w0F19lpgG2ftQl+Ldl9mR5YXgJaR/57+Ikjiry97U6u6SR Z44EUUcVC5PqJ3iz3fojpHRI87RMe3lT6onq/Ih9pP4VUL3Hcx2IA0kw2R6kcwLSGgPIGpihZ7GB4 +ZO459fA==; Received: from srv021.web.ichtushosting.com ([78.47.76.72]) by srv015.mail.ichtushosting.com stage1 with esmtp (Exim MailCleaner) id 1kmDh1-0002pu-1H for from ; Mon, 07 Dec 2020 11:24:32 +0100 Received: from ptr-fq9pjpi2vzycpmwwrgh.18120a2.ip6.access.telenet.be (ptr-fq9pjpi2vzycpmwwrgh.18120a2.ip6.access.telenet.be [IPv6:2a02:1812:c3c:3a00:8485:251f:b6a7:1b01]) (Authenticated sender: brendt@stitcher.io) by srv021.web.ichtushosting.com (Postfix) with ESMTPSA id B5CC520ED7 for ; Mon, 7 Dec 2020 11:24:29 +0100 (CET) X-MailCleaner-return_path: brendt@stitcher.io X-MailCleaner-sender_address: brendt@stitcher.io X-MailCleaner-recipients: internals@lists.php.net Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.4\)) Date: Mon, 7 Dec 2020 11:24:28 +0100 References: <32277b43-079d-4cd7-a159-8ad555096742@garfieldtech.com> <31c9d66b-771a-35ed-1b11-c681bbcc02c3@gmail.com> To: Levi Morrison via internals In-Reply-To: Message-ID: <66A17C7A-2781-42A7-898B-309E8B59650B@stitcher.io> X-Mailer: Apple Mail (2.3608.120.23.2.4) X-MailCleaner-TrustedIPs: Ok Subject: Re: [PHP-DEV] [RFC] Enumerations From: brendt@stitcher.io (Brent Roose) Hi Larry and Ilja It's great to see you're looking into enums, thanks! I have a few = considerations from a userland point of view. I've been maintaining a = userland enum implementation for a while now [1] so I think I share a = thing or two about my experience. - Scalar enums are spot on, exactly what I'd expect. - Support with match is awesome, and I think makes it so that array key = support isn't necessary. - Others already addressed that serialization and deserialization would = be a nice feature. A common use case is to store enums in a datastore of = some kind, and it would be nice not having to make dedicated factories = for them. - The `case` syntax feels quirky. I assume it's because PHP wouldn't = allow something like this: ``` enum Suit: string { Hearts =3D 'H'; Diamonds =3D 'D'; Clubs =3D 'C'; Spades =3D 'S'; } ``` Finally, I've got one (rather large) concern about object enums, = specifically with methods implemented on a per-enum basis. I did the = same [2] when I first implemented my userland package. =46rom my = research back then, I believe only Java [3] allowed this behaviour. If = you've checked out that link, you've seen that value specific methods = have been removed in v2. That's with good reason: they turned out to = rather cumbersome to maintain and even a bit useless. Here's why: - You example shows one method, the `color` one, which is still kind of = manageable. If you allow enum methods though, you'll often end up with = more than one method: `label`, `color`, `index`, `name`, `id`, are a few = that come to mind. In the end an enum grows very large and unmanageable, = with often lots of repeated code. - Enum value methods actually are the state pattern [4] in disguise. One = difference being that enums objects can't manage their own internal = state, so they become less useful in applying the state pattern compared = to using classes. I think enums shouldn't aim to solve the state pattern. It's out of = scope for what enums should do and their way of solving the state = pattern will be worse in practice compared to using classes. I'd say it = would be good to keep the defintion of enums in mind: > "an enumerated type [=E2=80=A6] is a data type consisting of a set of = named values called elements, members, enumeral, or enumerators of the = type. The enumerator names are usually identifiers that behave as = constants in the language." [5] "Named values" and "constants" being the keywords here, there's no = "behaviour" implemented by enum values, which is why only a small amount = of languages allow this kind of functionality. I realise enum objects might seem like a good idea to provide more = value-specific functionality in a concise way, but let's compare = per-value methods with a method on the base enum: ``` enum Suit implements Colorful { case Hearts { public function color(): string { return "Red"; } } =20 case Diamonds { public function color(): string { return "Red"; } } =20 case Clubs { public function color(): string { return "Black"; } } =20 case Spades { public function color(): string { return "Black"; } } =20 public function shape(): string { return "Rectangle"; } } ``` vs ``` enum Suit implements Colorful { case Hearts; case Diamonds; case Clubs; case Spades; public function color(): string { return match ($this) { Suit::Hearts, Suite::Diamonds =3D> "Red", Suit::Clubs, Suite::Spades =3D> "Black", } } } ``` In summary: - If you'd use enum objects for "simple functionality", I'd say `match` = will always be the more concise way. - If you'd use enum objects for handling complex state, you're better = off using classes and properly implementing the state pattern. I don't think enum objects should be a blocker, if people _really_ want = it then fine. Based on my experience though, I'm rather sure that they = won't be very useful, and would love to hear your opinion on the matter. Kind regards Brent [1] https://github.com/spatie/enum [2] https://github.com/spatie/enum/tree/v1#enum-specific-methods [3] https://www.geeksforgeeks.org/enum-in-java/ [4] https://en.wikipedia.org/wiki/State_pattern [5] https://en.wikipedia.org/wiki/Enumerated_type > On 7 Dec 2020, at 10:30, Rowan Tommins = wrote: >=20 > On 07/12/2020 01:00, Paul Crovella wrote: >> Instance state being global is a well-known problem with singletons. >> Maybe don't use singletons then. Or simply document them as was done >> in the RFC. I'd prefer the former since singletons don't seem to buy >> much here but problems, though maybe I'm missing something. >=20 >=20 > Yes, I think you are missing something - or maybe I am, because I = honestly can't picture what it would look like for enums *not* to be = singletons. >=20 > Would Suit::Hearts be a constructor, producing a new instance each = time, each with its own state? Would we then overload =3D=3D=3D, so that = Suit::Hearts =3D=3D=3D Suit::Hearts was still true somehow? >=20 >=20 > > In any case why is static state being (kinda sorta) restricted along = with it? >=20 >=20 > On the face of it, I agree, static properties could be supported. But = looking at the details of the current proposal, it might actually take = some thought to make them feel natural. As I understand it, each case = acts like a sub-class, which is useful for over-riding instance methods, = but would mean a static property would be defined separately on each = case: >=20 > enum Suit { > static $data; > case Hearts; > case Spades; > case Clubs; > case Diamonds; > } >=20 > Suit::$data =3D 42; > $mySuit =3D Suit::Hearts; > var_dump($mySuit::$data); // will not print 42, because = Suit::Hearts::$data is a different property >=20 >=20 > As Pierre says, the idea of backing enums onto objects is mostly an = implementation detail; their fundamental design is based on how enums = are generally used, and implemented in other languages. >=20 > Rather than "objects which are a bit enum-like", it might be useful to = frame them as "enums which are a bit object-like". The primary = consistency needs to be with what people will expect an enum to do. >=20 > Backing them onto objects makes it easy to add on any object-like = behaviour that feels useful, but once we've added it, it's much harder = to remove or change if we realise it's causing problems for users, or = getting in the way of other features. >=20 > That's why I was asking if you had use cases in mind, because I was = starting from that position: assume they have *no* features, and add the = ones we think are necessary and achievable. >=20 >=20 > Regards, >=20 > --=20 > Rowan Tommins (n=C3=A9 Collins) > [IMSoP] >=20 > --=20 > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php >=20