On Fri, 24 Jul 2020 at 14:43, Benjamin Eberlei <kont...@beberlei.de> wrote:

>
>
> On Fri, Jul 24, 2020 at 3:15 PM Chris Riley <t.carn...@gmail.com> wrote:
>
>> On Fri, 24 Jul 2020 at 14:01, Benjamin Eberlei <kont...@beberlei.de>
>> wrote:
>>
>>>
>>>
>>> On Fri, Jul 24, 2020 at 1:13 PM Chris Riley <t.carn...@gmail.com> wrote:
>>>
>>>> Hi all,
>>>>
>>>> The named parameters RFC has been accepted, despite significant
>>>> objections
>>>> from maintainers of larger OSS projects due to the overhead it adds to
>>>> maintaining backwards compatibility as it has now made method/function
>>>> parameter names part of the API; a change to them would cause a BC break
>>>> for any library users who decide to use the new feature.
>>>>
>>>
>>> Hi Chris,
>>>
>>> I had something similar in mind, but using an attribute. Here is a patch
>>> that already allows this:
>>>
>>>
>>> https://github.com/beberlei/php-src/commit/4b0a02f9c6ba579f93ec57c754fa3794a96c696b
>>>
>>> Idea: Have a @@NameAlias attribute, where you can provide a second name
>>> for the attribute. This would allow to refactor parameter names by adding
>>> the attribute with the old name as an alias.
>>>
>>>
>>>>
>>>> It is likely that the way this will shake out is that some maintainers
>>>> will
>>>> accept the additional overhead of including parameter names in their BC
>>>> guidelines and others will not, this leaves users unsure if they can use
>>>> the new feature without storing up issues in potentially minor/security
>>>> releases of the libraries they use. This is not really an ideal
>>>> situation.
>>>>
>>>> More pressing a point is that the current implementation breaks object
>>>> polymorphism. Consider this example (simplified from one of my
>>>> codebases)
>>>>
>>>> interface Handler {
>>>>     public function handle($message);
>>>> }
>>>>
>>>> class RegistrationHandler implements Handler {
>>>>     public function handle($registraionCommand);
>>>> }
>>>>
>>>> class ForgottenPasswordHandler implements Handler {
>>>>     public function handle($forgottenPasswordCommand);
>>>> }
>>>>
>>>> class MessageBus {
>>>>     //...
>>>>     public function addHandler(string $message, Handler $handler) {
>>>> //... }
>>>>     public function getHandler(string $messageType): Handler { //... }
>>>>     public function dispatch($message)
>>>>     {
>>>>         $this->getHandler(get_class($message))->handle(message:
>>>> $message);
>>>>     }
>>>> }
>>>>
>>>> This code breaks at run time.
>>>>
>>>> Proposals were made for resolutions to this issue however all of them
>>>> require trade offs and could potentially break existing code.
>>>>
>>>> My proposal to resolve these two issues is to add the ability to rename
>>>> parameters with a new syntax as follows.
>>>>
>>>> function callBar(Foo $internalName:externalName) {
>>>>     $internalName->bar();
>>>> }
>>>>
>>>> $x = new Foo();
>>>> callBar(externalName: $x);
>>>>
>>>> This allows both the above problems to be resolved, by renaming the
>>>> internal parameter and keeping the external signature the same.
>>>>
>>>> I propose that the RFC would have two voting options.
>>>>
>>>> The first would be to implement it as proposed above, this would allow
>>>> any
>>>> parameter to be called by name regardless of the intentions of the
>>>> author
>>>> of the method/function and is closest to the current behaviour.
>>>>
>>>> The second option would be to use this syntax to make named parameters
>>>> in
>>>> userland code explicitly opt in. As such an additional shortcut syntax
>>>> would be implemented: $: to designate a named parameter. eg
>>>>
>>>> function callBar($:externalName) {
>>>>     $externalName->bar();
>>>> }
>>>>
>>>> $x = new Foo();
>>>> callBar(externalName: $x);
>>>>
>>>> If a parameter is not opted in, a compile time error is raised:
>>>>
>>>> function callBar($externalName) {
>>>>     $externalName->bar();
>>>> }
>>>>
>>>> $x = new Foo();
>>>> callBar(externalName: $x); // Error: cannot call parameter
>>>> $externalName by
>>>> name.
>>>>
>>>> There are pros and cons to this second approach, on the one hand it
>>>> reduces
>>>> the usefulness of the named parameter syntax by requiring changes to old
>>>> code to enable it (although this could probably be automated fairly
>>>> easily)
>>>> however it does provide a neater solution to the second problem in
>>>> that, to
>>>> prevent the runtime errors in the second issue example, every child
>>>> class
>>>> would need to use the rename syntax on it's parameter to prevent errors,
>>>> whereas if we went down this route, the parent class could just not opt
>>>> into the named parameter syntax and the code would function as expected.
>>>>
>>>> Another advantage is that with the ability to rename parameters using
>>>> the
>>>> opt in, we gain some flexibility to tighten up the LSP rules relating to
>>>> named parameter inheritance.
>>>>
>>>> class Foo {
>>>>     public function bar($:param) { //... }
>>>>     public function baz($internal:external) { //... }
>>>> }
>>>>
>>>> // OK
>>>> class Bar {
>>>>     public function bar($renamed:param) { //... }
>>>>     public function baz($renamed:external) { //... }
>>>> }
>>>>
>>>> // Compile time error cannot rename named parameter $:param (renamed to
>>>> $:renamedParam)
>>>> class Baz {
>>>>     public function bar($:renamedParam) { //... }
>>>> }
>>>>
>>>> // Compile time error cannot rename named parameter $:external (renamed
>>>> to
>>>> $:renamed)
>>>> class Baz {
>>>>     public function baz($internal:renamed) { //... }
>>>> }
>>>>
>>>> While this would be technically possible with the first option (no opt
>>>> in)
>>>> it would break any existing code which renames a parameter as every
>>>> parameter would be subject to these rules.
>>>>
>>>> I don't have Wiki karma so can't post this yet; but I want to get the
>>>> ball
>>>> rolling on discussion as feature freeze is coming up fast and if we
>>>> want to
>>>> go for the second option, that must hit before the named parameter
>>>> syntax
>>>> is in a tagged version of PHP.
>>>>
>>>> Regards,
>>>> Chris
>>>>
>>>
>> Hi,
>>
>> While the attribute idea does solve the BC problems, I'm not seeing how
>> it really solves the polymorphism issue - could you provide an example of
>> how this would work?
>>
>> In either case; as a personal preference I'd rather stick to syntax that
>> affects the parameter as part of it's definition instead of tweaking it's
>> behaviour with an attribute. It just feels easier to grasp what is going on.
>>
>
> Attributes are part of the declaration from PHP 8 on, and make them prime
> implementation device for this kind of functionality, because they don't
> require new keywords (same goes for ReadOnly and many other proposals that
> were shot down leading up to PHP 8).
>
> You are right about poloymorphism, that would "only" work when every
> implementation adds @@NameAlias("message"). You could devise another
> attribute for this that gets inherited: @@InheritName or something (with
> probably a better name needing to be found).
>

Do you have an implementation example of using attributes that can be added
to the RFC: https://wiki.php.net/rfc/renamed_parameters

Thanks,
Chris

Reply via email to