Hi Nicolas,

On Fri, 24 Jun 2022 at 17:38, Nicolas Grekas
<nicolas.grekas+...@gmail.com> wrote:
>
> I'm now considering withdrawing the RFC because I don't see a way forward
> that could be consensual enough.

Just in general, I think changes to the type system are always going
to take longer than a few weeks to discuss. There are always going to
be subtle implications that need to be thought through thorougly.

Also, the argument for a change to the type system like this should be
based on why it's the right thing to do for new code that is being
written. Although obviously everyone who has a large code base wants
to be able to upgrade to the latest and greatest PHP to get the new
features at the lowest cost in changing code, imo it's more important
long term to get the language right, rather than putting too much
emphasis on lowering the cost of upgrading.

>> Derick wrote:
>> My concern is that auto implementing __toString, will lead to decreasing
>> type safety of enums in weak typing mode, since they get auto-casted to
>> string when passed to a function accepting strings. This effectively adds
>> more type juggling cases.
>
> I don't share this concern: if an API accepts a string and the engine can
> provide a string,

function/method calls are not the only place were type comparisons are done.

My understanding is that if this RFC is passed, then the situation would be:

Foo::Bar == 'Bar'; // true
Baz::Bar == 'Bar'; // true
Baz::Bar == Foo::Bar; // false

Which is not obviously the correct thing.

There is also the issue that callbacks called internally by the engine
are always in weak/coercive mode. That means that changes to
weak/coercive can leak through to code that wants to always be in
strict mode.

> It would be great if we could find ways to make it easier for general-purpose
> libraries to support enums without cluttering libraries with if/else blocks
> and without changing existing interfaces in a backwards-incompatible way.

There's two parts going on here. First, yes, enums could probably be
easier to work with, and we should probably be looking how to do that.

Second is an argument about how easy it should be to retrofit new
features to existing code. Although I can see why people would want
that, it's a lot harder to justify it.

> As experienced on the Symfony repository, this problem is especially visible
> at the boundary of libraries: when some component accepts a string as input,
> ppl want them to also accept backed-enums. This usually means that they
> propose widening the accepted types of some method to make them work
> seamslessly with enums.

Doing that appears to be a violation of the "open for extension,
closed for modification" principle.

If you want to change the type signature, introducing a new function
is almost certainly the 'right' thing to do, even if that means more
work for people with large existing code-bases. e.g.

Change:
class Foo {
   function bar(string $quux) {}
}

To this:
class Foo {
   function bar(string $quux) {}
   function barEx(string|SomeEnum $quux) {}
}

And eventually deprecate the original bar method.

> but we also have a case in Symfony where defining service
> definitions in yaml doesn't work with enums because there
> is no way to express the "->value" part.

I very strongly think the limitations of what yaml config file choices
were made in a downstream project should not influence the design of a
the type system of an upstream project. I'm pretty sure that a
successful RFC isn't going to need to mention that problem.

> If other ppl share my concerns and have a proposal, please let us know.

It might be hard to have a one size fits all rule, hard-coded in the
engine as people genuinely have different views of what enums are.

One idea that I think may have been mentioned before (and if I recall,
shot down pretty hard) would be to allow people to register cast
callbacks similar to the code below. That would allow people who view
enums as special constants to cast away, and those view enums as
types, to not cast.

This currently would be problematic for the same reason that PHP ini
settings are problematic; without a module or package system, any
settings that affect how the engine behave affect all code that is
run, rather than being limited to just the library that wants to
enable that setting. Which is a problem that keeps rearing it's head.

Maybe someone sponsoring some blue-sky research on how feasible a
module/package system could be, would make addressing problems similar
to the one here be easier to work on.

cheers
Dan
Ack


enum Suit: string {
    case Hearts = 'H';
    case Spades = 'S';
}

function foo(string $bar) {
    var_dump($bar);
}

function cast_backed_enum_to_string(BackedEnum $enum): string {
    return $enum->value;
}

register_cast_callback(
    BackedEnum::class, // source type
    'string',           // target type
    cast_backed_enum_to_string(...)
);

foo(Suit::Hearts);
// Engine sees we have a BackedEnum and that foo wants a
// string, so calls cast_backed_enum_to_string to do the conversion

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to