Re: [IDEA] allow extending enum
| From: | Mark Baker | Date: | Wed, 29 Mar 2023 16:28:53 +0000 |
| Subject: | Re: [IDEA] allow extending enum | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-119779@lists.php.net to get a copy of this message | ||
On 29/03/2023 16:43, Mark Baker wrote:
On 29/03/2023 16:31, Davey Shafik wrote:enum HttpErrors {That would make a lot of sense, and I was just having similar thoughts myself. ApiErrors isn't the same enum, or an extension of HttpErrors: it's a new Enum, but it does include all HttpErrors cases (and methods) without the need to duplicate code, and any new cases that are subsequently added to HttpErrors will automatically be incorporated in ApiErrors. Another benefit of this approach would be to allow the inclusion of multiple enums, in the same way that we can include multiple traits.On Mar 29, 2023, at 06:56, Rowan Tommins <rowan.collins@gmail.com> wrote: On Wed, 29 Mar 2023 at 14:22, Rokas Šleinius <raveren@gmail.com> wrote:The issue of contention here is that inheritance isn't the correct mechanism for reusing enum definitions to expand on them. What about allowing "use" syntax like traits? enum HttpErrors {Ok so I am trying to find the argumentation here:From a theory point of view, *any* type definition is about limiting allowed values. The difference between "mixed" and "integer" is that "mixed" allows both 'Hello' and 42, but "integer" does not - it defines a tighter limit. In the same way, saying "I accept an error code" means "I accept an error code *and nothing else*" - the definition of what is and what isn't an "error code" is deliberately a *limit* on the values that you accept.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..?An enum is a type, so that's why George was talking about types. He was making the same point, in different words, as I did: the relationship between types implied by the keyword "extends" is not the relationship you want in this case.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*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.This is the key point - if you pass an error code that didn't previously exist, the existing system *won't* be able to handle it. That's why enums are inherently restrictive: the system wants to be able to say "this is the list of error codes I understand, don't give me anything else". If you have a system that accepts the new codes as well as the old ones, you can use a union type declaration as George says: enum AdditionalErrorCode { case Code_456; } class ExtendedErrorHandler extends StandardErrorHandler { public function handle(StandardErrorCode|AdditionalErrorCode $code) {switch ( $code ) { case AdditionalErrorCode::Code_456: // handling for new code goes here break; default: // assert($code instanceof StandardErrorCode); parent::handle($code); break; }} }case HTTP_STATUS_400; case HTTP_STATUS_401; …} enum ApiErrors {use HttpErrors;case JsonParserError; case GraphQLParserError;} Now you have ApiErrors::HTTP_STATUS_400 etc without ApiErrors being is-a HttpErrors.
case HTTP_STATUS_400;
case HTTP_STATUS_401;
…} enum DatabaseErrors {
case RECORD_NOT_FOUND; case DATABASE_NOT_AVAILABLE;
…} enum ApiErrors {
use HttpErrors, DatabaseErrors;
case JsonParserError;
case GraphQLParserError;} -- Mark Baker