Re: Let's discuss enums!
| From: | Stephen Coakley | Date: | Fri, 18 Sep 2015 02:58:57 +0000 |
| Subject: | Re: Let's discuss enums! | ||
| References: | 1 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-88312@lists.php.net to get a copy of this message | ||
On 09/17/2015 06:06 PM, Rowan Collins wrote:
Hi All, This has come up in passing a few times recently, but I'm not sure there's ever been a dedicated discussion of it: would it be useful for PHP to have a built-in Enumeration type, and if so, how should it look? Many other languages have enum types, with varying functionality. The central concept is always that there's some declared type with a bunch of named constants, but beyond that there's a lot of variability: for starters, is it a type of object, a special way of naming integers, or an uncomparable type more like booleans and nulls? Here are my thoughts on what I'd like from a PHP enum - I'm not using "should" in a particularly strong sense, it's just a way of framing the points of discussion: 1) enums should act like values, not mutable objects; an array-style copy-on-write behaviour would be possible, but it feels wrong to me to store any state in an enum variable, so just plain immutable would be my preference 2) the members of an enum should have a name which is accesible as a string, e.g. Weekdays::SUNDAY->getName() == 'SUNDAY' 3) there should be no accessible "value" for a member; the value of Weekdays::SUNDAY is simply Weekdays::SUNDAY, not 0 or 7 or 'SUNDAY' (I'm thinking that internally, each member would be represented as an object pointer, so there's no real benefit to forcing people to number everything like some languages do) 4) each enum member should be considered a singleton, in the sense that you can't construct or destroy one, only reference them; all possible instances would be created as soon as the enum was defined 5) following from (3) and (4), an enum value should compare equal only to itself, unlike in C# for instance, where it would be comparable to an integer based on its numeric value; similarly it shouldn't be possible to cast to or from an enum 6) an enum should be able to have additional fields; these would be initialised in the enum's definition; this is inspired by Java and Python's ability to pass parameters to the "constructor" of the enum, but it feels weird to me for any logic to happen in that constructor other than simple assignments, so I'm thinking of a simpler syntax and implementation. It also simplifies immutability if no userland code ever writes to the properties. There may be an important use case for constructor logic I'm missing though? 7) an enum should have default static methods for accessing all the members of the enum as an associative array 8) enums should be a first-class type, is_object(Weekdays::SUNDAY) should return false, for instance; maybe Weekdays::SUNDAY instanceof Weekdays should return true though 9) additional static and instance methods should be definable, bearing in mind the immutability constraints already discussed Given the above, I think we might end up with something like this: enum Weekdays {Member is even a little too much IMO. A comma-separated list syntax would be better, simply because its shorter and more similar to enum syntax on other languages.member MONDAY; // if there are no fields to initalise, the memberjust needs its name declaringmember TUESDAY ( 2, 'Chewsdae' ); // positional arguments forpopulating fields in the order they are defined; a bit like Java, but without the constructormember WEDNESDAY { $dayNumber = 3, $sillyName = 'Wed Nose Day' };// or maybe a named-parameter syntax to make things clearermember THURSDAY, FRIDAY, SATURDAY, SUNDAY; // don't force people towrite each entry on its own line; maybe even the "member" keyword is too much?
Not sure if this could be allowed, but simply using name interpolation would be better. e.g.:public $dayNumber, $sillyName; // fields initialised for each memberpublic static function getWeekend() { return [ self::SATURDAY, self::SUNDAY ]; }public function getZeroIndexedDayNumber() { return $this->dayNumber - 1; }} $today = Weekdays::THURSDAY; foreach ( Weekdays::getMembers() as $day_name => $day ) {echo $day->dayNumber; if ( $day == $today ) { echo "Today!"; } else { echo $day_name; // equivalently: echo $day->getName(); }} // Do we need a static method to access a member by name, or is this good enough? $favourite_day = Weekdays::getMembers()[ $_GET['fav_day'] ];
$favourite_day = Weekdays::$_GET['fav_day'];Similar to $object->$name and nothing to do with StaticClass::$property syntax.
So, what are anyone's thoughts? Am I rambling on too much as usual? ;) Regards,Is there any interest in enum subtypes? As in, allowing each member to also be a class? This would allow algebraic data typing, which would be a pretty powerful addition to the language. -- Stephen