Re: [RFC] [Under Discussion] Auto-implement Stringable for string backed enums

From: Date: Wed, 22 Jun 2022 21:43:46 +0000
Subject: Re: [RFC] [Under Discussion] Auto-implement Stringable for string backed enums
References: 1 2 3  Groups: php.internals 
Request: Send a blank email to internals+get-118066@lists.php.net to get a copy of this message
On 22/06/2022 18:26, Larry Garfield wrote:
The argument presented is that it's easier to type AppRoles::Admin than "admin", because the former provides you with an error if you typo something. That's a valid argument, but... not for using enums. It's an argument for using constants.
I wonder if the reality is that neither enums (as implemented) nor constants are the right solution to to this. What users want is some way to say "this value should be a string, but in this context it should be one of this list of strings"; or, sometimes, "is this string one of this list of strings?" Constants can't do that - they give you a way of referring to the possible values, but no tools for enforcing or testing against them. Backed enums can kinda sorta do that with a bit of effort, using ->value and ::tryFrom, but they're not really built for it. A better fit would be some kind of "domain type", which would allow you to write something vaguely like this: domain SymfonyPermission: string; domain AcmePermission: string { 'admin' | 'user' | 'bot' }; assert( in_domain('admin', SymfonyPermission) ); assert( in_domain('admin', AcmePermission) ); assert( in_domain('random stranger', SymfonyPermission) ); assert( ! in_domain('random stranger', AcmePermission) ); Domains can also be considered sets, which you could compare directly, and maybe even calculate intersections, unions, etc: assert( is_subset(AcmePermission, SymfonyPermission) ); The actual values would be ordinary strings, and type constraints would just be checking the value passed against the domain: function doSymfonyThing(SymfonyPermission $permission) {
    echo $permission; // no coercion needed, $permission is a string
} function doAcmeThing(AcmePermission $permission) {
    doSymfonyThing($permission);
} doAcmeThing('admin'); // no special syntax needed to "construct" or "look up" an instance Crucially, this solves the described problem of a library accepting an infinite (or perhaps just very wide) set of values, and a consuming app wanting to constrain that set within its own code. It's one disadvantage is the typo-proofing and look up availability that constants give, but you could always combine the two. Regards, -- Rowan Tommins [IMSoP]

« previous php.internals (#118066) next »