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.
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
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.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. egfunction 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
For reference, I believe you are proposing something
close to Swift external names but way more complex.
Ty,
Márcio
Hi
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.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. egfunction 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,
ChrisFor reference, I believe you are proposing something
close to Swift external names but way more complex.Ty,
Márcio
Hi,
I've never written any code in swift, however having quickly read the
documentation I think that my proposal is almost identical to swift
argument labels if the first option is chosen. It's interesting to note
that swift provides an explicit opt out of named parameters instead of an
opt in (by giving it a _ for it's external name) this could be an
alternative option for this RFC, although I'd propose the $: syntax in that
instance. You'd lose the ability to do compile time checks on parameter
renames in child classes; but it might provide a pragmatic middle ground
between my two proposed options.
Thanks,
Chris
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. egfunction 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 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. egfunction 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.
Regards,
Chris
On Fri, 24 Jul 2020 at 14:01, Benjamin Eberlei kontakt@beberlei.de
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. egfunction 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,
ChrisHi,
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).
Regards,
Chris
On Fri, 24 Jul 2020 at 14:01, Benjamin Eberlei kontakt@beberlei.de
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. egfunction 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,
ChrisHi,
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
As a general point, Python went through this almost 2 years ago. Their PEP
is worth reading (I didn't see it mentioned before):
https://www.python.org/dev/peps/pep-0570/
Peter
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.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. egfunction 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 all,
Following up from this I've created a draft RFC:
https://wiki.php.net/rfc/renamed_parameters will move to in discussion once
I've ensured everything important has been captured.
Regards,
Chris
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.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. egfunction 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 all,
Following up from this I've created a draft RFC:
https://wiki.php.net/rfc/renamed_parameters will move to in discussion
once
I've ensured everything important has been captured.Regards,
Chris
You added PHP 8.0 as a propsoed version, but that will not be possible
anymore 2 weeks of discussion + 2 weeks of voting are not possible to fit
in before the feature freeze, which is in 11 days.
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.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. egfunction 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
Am 24.07.2020 um 16:11 schrieb Benjamin Eberlei kontakt@beberlei.de:
Hi all,
Following up from this I've created a draft RFC:
https://wiki.php.net/rfc/renamed_parameters will move to in discussion
once
I've ensured everything important has been captured.Regards,
ChrisYou added PHP 8.0 as a propsoed version, but that will not be possible
anymore 2 weeks of discussion + 2 weeks of voting are not possible to fit
in before the feature freeze, which is in 11 days.
Hey Benjamin,
While you are technically correct, the primary point of a feature freeze is not allowing in completely new features.
It will always happen that there are changes and extensions to RFCs introduced for the next version which may need to be addressed first, because there is massive benefit to the new feature in that case. (from a backwards/forwards compatibility standpoint for example)
I do not necessarily agree with the RFC (not given it much thought yet), but I think such RFCs shall still be able to be introduced later on (well, not in RC phase, but a bit after the feature freeze cutoff), if there is actual benefit from them not being deferred to the next version. Ultimately, the RM has to make the call (also to avoid indefinite delays or filibustering or such).
Bob
Am 24.07.2020 um 16:11 schrieb Benjamin Eberlei kontakt@beberlei.de:
Hi all,
Following up from this I've created a draft RFC:
https://wiki.php.net/rfc/renamed_parameters will move to in discussion
once
I've ensured everything important has been captured.Regards,
ChrisYou added PHP 8.0 as a propsoed version, but that will not be possible
anymore 2 weeks of discussion + 2 weeks of voting are not possible to fit
in before the feature freeze, which is in 11 days.Hey Benjamin,
While you are technically correct, the primary point of a feature freeze
is not allowing in completely new features.
It will always happen that there are changes and extensions to RFCs
introduced for the next version which may need to be addressed first,
because there is massive benefit to the new feature in that case. (from a
backwards/forwards compatibility standpoint for example)I do not necessarily agree with the RFC (not given it much thought yet),
but I think such RFCs shall still be able to be introduced later on (well,
not in RC phase, but a bit after the feature freeze cutoff), if there is
actual benefit from them not being deferred to the next version.
Ultimately, the RM has to make the call (also to avoid indefinite delays or
filibustering or such).
We should of course be open to making minor adjustments due to
unanticipated issues after feature freeze -- after all, that's where we
gain experience with new features. The emphasis here is very much on
minor and unanticipated though.
None of the issues this RFC tries to address, or even the approaches it
suggests, are new. This has already been discussed during the main proposal
-- and not just as a side mention, this was the core controversy of the
named parameters proposal.
I am open to discussing minor amendments like Benjamin's suggestion for a
parameter alias attribute, if we think it important to introduce it in PHP
8.0 rather than at a later time. But making a switch to opt-in named
parameters? That's essentially a completely different feature and we
certainly cannot accept such a fundamental change past feature freeze.
Regards,
Nikita
You added PHP 8.0 as a proposed version, but that will not be possible
anymore 2 weeks of discussion + 2 weeks of voting are not possible to
fit
in before the feature freeze, which is in 11 days.While you are technically correct, the primary point of a feature freeze
is not allowing in completely new features.
It will always happen that there are changes and extensions to RFCs
introduced for the next version which may need to be addressed first,
because there is massive benefit to the new feature in that case. (from
a
backwards/forwards compatibility standpoint for example)We should of course be open to making minor adjustments due to
unanticipated issues after feature freeze -- after all, that's where we
gain experience with new features. The emphasis here is very much on
minor and unanticipated though.
Endorsing this. Anything post FF needs to be held to a high standard.
Minor and Unanticipated changes.
- The option to set alt-names on parameters is substantial.
- Making named params explicitly opt-in is less substantial (though
certainly not trivial), especially if it were hung off an attribute which
would mean no actual new syntax, but Niki's point that it wasn't an unknown
or unanticipated issue stands.
I share OP's worry that this pushes workload onto library and framework
maintainers, and I wouldn't look forward to the review of all APIs to make
sure their names are correct, but the vote has spoken. We should
absolutely continue pursuing this topic with an eye to 8.1 so that library
updates are less painful moving forward.
-Sara
On Fri, Jul 24, 2020 at 10:10 AM Nikita Popov nikita.ppv@gmail.com
wrote:You added PHP 8.0 as a proposed version, but that will not be
possible
anymore 2 weeks of discussion + 2 weeks of voting are not possible
to fit
in before the feature freeze, which is in 11 days.While you are technically correct, the primary point of a feature
freeze
is not allowing in completely new features.
It will always happen that there are changes and extensions to RFCs
introduced for the next version which may need to be addressed first,
because there is massive benefit to the new feature in that case.
(from a
backwards/forwards compatibility standpoint for example)We should of course be open to making minor adjustments due to
unanticipated issues after feature freeze -- after all, that's where we
gain experience with new features. The emphasis here is very much on
minor and unanticipated though.Endorsing this. Anything post FF needs to be held to a high standard.
Minor and Unanticipated changes.
- The option to set alt-names on parameters is substantial.
- Making named params explicitly opt-in is less substantial (though
certainly not trivial), especially if it were hung off an attribute which
would mean no actual new syntax, but Niki's point that it wasn't an unknown
or unanticipated issue stands.I share OP's worry that this pushes workload onto library and framework
maintainers, and I wouldn't look forward to the review of all APIs to make
sure their names are correct, but the vote has spoken. We should
absolutely continue pursuing this topic with an eye to 8.1 so that library
updates are less painful moving forward.-Sara
Hi,
My main concern with named params as they currently stand is that they are
fully enabled: if we release PHP 8.0 with named params as they are now,
there's no take backsies. Fixing the polymorphism issue and the maintenance
issues become much harder as you have to work around the fact that there
will be userland code relying on the feature as shipped. If we target
fixing this in 8.1 we would lose the option of being able to make named
params explicitly opt in and as such any possibility of a strict solution
to the polymorphism issues that it throws up.
Regards,
Chris
TLDR
Only consider parameter names from a type-hinted interface, ignore
parameter names from the actual class.
I had a look at
https://wiki.php.net/rfc/named_params#to_parameter_name_changes_during_inheritance
Indeed I have concerns about this, because a call with named arguments
would make your code incompatible with 3rd party implementations of the
interface that do not keep the parameter names.
I would see this as a flaw in a newly added feature, which should be fixed
during the feature freeze.
I might even say the current version as described in the RFC is broken.
I have no objection to the OP's proposal, but would like to add some
alternative ideas to the discussion.
My first idea would be to only consider the parameter names in the original
interface, and ignore all renamed parameters in sub-classes.
This would cause problems if a class implements multiple interfaces that
declare the same method, but with different parameter names.
So, a better idea would be like this:
- The variable must be type-hinted with an interface. E.g. as a parameter
or as object properties. - named arguments always use the parameter names from the type-hinted
interface.
This would need some static analysis at compile time, and we need to be
able to type-hint regular local variables.
An alternative would be to somehow "import" the parameter names at the top
of the file, somehow like so:
use Acme\Animal::bar; // Parameter names from this method will be used.
(this syntax probably needs more thought).
Yet another option would be to somehow specify the interface in the method
call..
((\Acme\Animal) $instance)->foo(a: 'A', b: 'B');
Regards
Andreas
On Fri, Jul 24, 2020 at 10:10 AM Nikita Popov nikita.ppv@gmail.com
wrote:You added PHP 8.0 as a proposed version, but that will not be
possible
anymore 2 weeks of discussion + 2 weeks of voting are not possible to
fit
in before the feature freeze, which is in 11 days.While you are technically correct, the primary point of a feature
freeze
is not allowing in completely new features.
It will always happen that there are changes and extensions to RFCs
introduced for the next version which may need to be addressed first,
because there is massive benefit to the new feature in that case. (from
a
backwards/forwards compatibility standpoint for example)We should of course be open to making minor adjustments due to
unanticipated issues after feature freeze -- after all, that's where we
gain experience with new features. The emphasis here is very much on
minor and unanticipated though.Endorsing this. Anything post FF needs to be held to a high standard.
Minor and Unanticipated changes.
- The option to set alt-names on parameters is substantial.
- Making named params explicitly opt-in is less substantial (though
certainly not trivial), especially if it were hung off an attribute which
would mean no actual new syntax, but Niki's point that it wasn't an unknown
or unanticipated issue stands.I share OP's worry that this pushes workload onto library and framework
maintainers, and I wouldn't look forward to the review of all APIs to make
sure their names are correct, but the vote has spoken. We should
absolutely continue pursuing this topic with an eye to 8.1 so that library
updates are less painful moving forward.-Sara
Hello all,
I would like to make my own alternative proposal from my previous message
more concrete.
I am going to describe a version that is not compatible with the existing
RFC at https://wiki.php.net/rfc/named_params.
It could be modified to be an extension to the existing, accepted RFC for
named parameters.
But I think it is useful to discuss this version first.
- Calls with named arguments can only happen on:
- explicitly named functions (e.g. no
call_user_func()
). - constructor calls with an explicitly named class.
- object methods, if the object variable is type-hinted or a type is
known at compile time.
- Named arguments in calls are converted to number-indexed arguments at
compile time. - Parameter name lookup is done based on the type-hinted class or
interface. Parameter names on the actual object are ignored.
Example:
interface I {
function setBackgroundColor($bgcolor);
}
interface J {
function setBackgroundColor($background_color);
}
class C implements I, J {
function setBackgroundColor($color) {}
}
class X {
private J $colorable;
function foo(I $colorable) {
// Good: Parameter names from "I::setBackgroundColor()" are used.
$colorable->setBackgroundColor(bgcolor: 'green');
// Error: Unknown parameter name for I::setBackgroundColor().
$colorable->setBackgroundColor(color: 'green');
// Error: Unknown parameter name for I::setBackgroundColor().
$colorable->setBackgroundColor(background_color: 'green');
// Good: Parameter names from "J::setBackgroundColor()" are used.
$this->colorable->setBackgroundColor(background_color: 'green');
}
}
// Parameter names from C::setBackgroundColor() will be ignored within
->foo().
(new X())->foo(new C());
Future extensions:
Allow to define "descriptive pseudo-interfaces" to provide reliable
parameter names, if the original package cannot be trusted to keep
parameter names stable.
interface K describes I {
function setBackgroundColor($color);
}
function foo(K $colorable) {
// Parameter names from K::setBackgroundColor() are used.
$colorable->setBackgroundColor(color: 'green');
}
// Parameter names from C::setBackgroundColor() will be ignored within
foo().
foo(new C());
Why?
This version of named parameters can be used with any existing old
interface.
It is compatible with any 3rd party library that may implement an interface
with renamed parameters.
It also allows inheritance from multiple "equivalent" interfaces which use
different parameter names.
Only the package that defines the interface needs to keep the parameter
names stable between versions.
How to make this compatible with the existing RFC?
We could introduce an alternative method call syntax for calls that should
take parameter names from a specific interface, instead of the actual class
instance.
Eg.
$obj->{J::setBackgroundColor}(background_color: 'green');
This would be undesirably verbose for long interface names..
Best
Andreas
TLDR
Only consider parameter names from a type-hinted interface, ignore
parameter names from the actual class.
I had a look at
https://wiki.php.net/rfc/named_params#to_parameter_name_changes_during_inheritance
Indeed I have concerns about this, because a call with named arguments
would make your code incompatible with 3rd party implementations of the
interface that do not keep the parameter names.
I would see this as a flaw in a newly added feature, which should be fixed
during the feature freeze.
I might even say the current version as described in the RFC is broken.I have no objection to the OP's proposal, but would like to add some
alternative ideas to the discussion.My first idea would be to only consider the parameter names in the
original interface, and ignore all renamed parameters in sub-classes.
This would cause problems if a class implements multiple interfaces that
declare the same method, but with different parameter names.So, a better idea would be like this:
- The variable must be type-hinted with an interface. E.g. as a parameter
or as object properties.- named arguments always use the parameter names from the type-hinted
interface.This would need some static analysis at compile time, and we need to be
able to type-hint regular local variables.An alternative would be to somehow "import" the parameter names at the top
of the file, somehow like so:use Acme\Animal::bar; // Parameter names from this method will be used.
(this syntax probably needs more thought).
Yet another option would be to somehow specify the interface in the method
call..((\Acme\Animal) $instance)->foo(a: 'A', b: 'B');
Regards
AndreasOn Fri, Jul 24, 2020 at 10:10 AM Nikita Popov nikita.ppv@gmail.com
wrote:You added PHP 8.0 as a proposed version, but that will not be
possible
anymore 2 weeks of discussion + 2 weeks of voting are not possible
to
fit
in before the feature freeze, which is in 11 days.While you are technically correct, the primary point of a feature
freeze
is not allowing in completely new features.
It will always happen that there are changes and extensions to RFCs
introduced for the next version which may need to be addressed first,
because there is massive benefit to the new feature in that case.
(from
a
backwards/forwards compatibility standpoint for example)We should of course be open to making minor adjustments due to
unanticipated issues after feature freeze -- after all, that's where we
gain experience with new features. The emphasis here is very much on
minor and unanticipated though.Endorsing this. Anything post FF needs to be held to a high standard.
Minor and Unanticipated changes.
- The option to set alt-names on parameters is substantial.
- Making named params explicitly opt-in is less substantial (though
certainly not trivial), especially if it were hung off an attribute which
would mean no actual new syntax, but Niki's point that it wasn't an
unknown
or unanticipated issue stands.I share OP's worry that this pushes workload onto library and framework
maintainers, and I wouldn't look forward to the review of all APIs to make
sure their names are correct, but the vote has spoken. We should
absolutely continue pursuing this topic with an eye to 8.1 so that library
updates are less painful moving forward.-Sara
Hi Andreas Hennings,
- Calls with named arguments can only happen on:
- explicitly named functions (e.g. nocall_user_func()
).
- constructor calls with an explicitly named class.
- object methods, if the object variable is type-hinted or a type is known at compile time.
This proposal would seem to depend on moving opcache into core, among other things.
Depending on how it's implemented, the condition of "a type is known at compile time" may also depend on whatever opcache optimization passes were enabled,
which would make the behavior of whether this throws an Error at runtime unintuitive to users.
(e.g. $a = SOME_OPTIMIZABLE_CONDITION ? new A() : new B(); $a->someMethod(namedArg: value);
)
-
SOME_OPTIMIZABLE_CONDITION
may depend on the php version or environment (e.g.PHP_OS_FAMILY == 'Windows'
)
A recent secondary poll on a rejected RFC I proposed did indicate broad interest in moving opcache to php's core,
but I doubt that'd be done in 8.0 due to the feature freeze, and I also doubt optimizations would always be enabled because of the overhead of optimization for small short-lived scripts
( https://wiki.php.net/rfc/opcache.no_cache#if_you_voted_no_why )
Also, the times when a type is known (with 100% certainty) at compile time are known by opcache but unintuitive to users,
due to the highly dynamic nature of PHP
($$var = 'value'
, references, calls to require()/extract() modifying the scope, globals being effectively modifiable at any time, etc.)
Even for typed properties, the existence of magic methods such as __get()
(e.g. in subclasses) means that the type of $this->prop at runtime is uncertain.
-
__get()
is called if it exists when a declared fetched property (typed or otherwise) was unset.
Regards,
- Tyson
Hi Andreas Hennings,
- Calls with named arguments can only happen on:
- explicitly named functions (e.g. no
call_user_func()
).- constructor calls with an explicitly named class.
- object methods, if the object variable is type-hinted or a type is
known at compile time.This proposal would seem to depend on moving opcache into core, among
other things.
Depending on how it's implemented, the condition of "a type is known at
compile time" may also depend on whatever opcache optimization passes were
enabled,
which would make the behavior of whether this throws an Error at runtime
unintuitive to users.
Obviously there would need to be a consistent definition about how the type
of a variable should be determined.
And there would need to be a way to determine this at runtime, in case that
opcache is not enabled.
This could be the same system that is responsible for runtime type checks.
Perhaps we should drop the "is known at compile time" and only support
explicit type hints.
Anything we do here should be dumb static analysis, not smart static
analysis.
E.g.
function foo(I $obj) {
$obj->setColor(color: 'blue'); // Good, based on I::setColor().
$obj2 = $obj;
$obj2->setColor(color: 'blue'); // Error, because simple static analysis
cannot determine the type of $obj2.
}
(e.g.
$a = SOME_OPTIMIZABLE_CONDITION ? new A() : new B(); $a->someMethod(namedArg: value);
)
Any "optimizable condition" would have to be treated like a regular
variable with unknown value.
So in the above case, named arguments would not be allowed.
SOME_OPTIMIZABLE_CONDITION
may depend on the php version or
environment (e.g.PHP_OS_FAMILY == 'Windows'
)A recent secondary poll on a rejected RFC I proposed did indicate broad
interest in moving opcache to php's core,
but I doubt that'd be done in 8.0 due to the feature freeze, and I also
doubt optimizations would always be enabled because of the overhead of
optimization for small short-lived scripts
( https://wiki.php.net/rfc/opcache.no_cache#if_you_voted_no_why )Also, the times when a type is known (with 100% certainty) at compile time
are known by opcache but unintuitive to users,
due to the highly dynamic nature of PHP
($$var = 'value'
, references, calls to require()/extract() modifying the
scope, globals being effectively modifiable at any time, etc.)
Even for typed properties, the existence of magic methods such as
__get()
(e.g. in subclasses) means that the type of $this->prop at
runtime is uncertain.
__get()
is called if it exists when a declared fetched property (typed
or otherwise) was unset.
Good point.
One thing to note, it seems __get() is only called when the property is
accessed from outside.
https://3v4l.org/sY96q (just a snapshot, play around with this as you feel)
I personally don't really care that much about public properties, I could
happily live in a world where named parameters are not available for
objects in public properties.
Or alternatively, we could say that it is the responsibility of the __get()
method to return an object that is compatible with the type hint on the
public property, IF named parameters are used.
Even if all of this does not work, I think the idea still has merit:
Evaluate the parameter names based on a known interface, instead of an
unknown implementation which may come from a 3rd party.
Perhaps a type hint is not the best way to determine this interface..
Greetings
Andreas
Regards,
- Tyson
Hi Andreas,
- Calls with named arguments can only happen on:
- explicitly named functions (e.g. no
call_user_func()
).- constructor calls with an explicitly named class.
- object methods, if the object variable is type-hinted or a type is
known at compile time.- Named arguments in calls are converted to number-indexed arguments at
compile time.- Parameter name lookup is done based on the type-hinted class or
interface. Parameter names on the actual object are ignored.
While this is an interesting concept in general, it introduces a much
larger change to the semantics of the language than seems justified for
this particular problem - it would effectively require introducing an
element of "static typing" into the language.
By "static typing", I mean this:
variables have an intrinsic type, and the same value can behave
differently depending on the type of variable that holds it
Which could be contrasted with "dynamic typing" like this:
values have an intrinsic type, and operations will be selected based
on those values, regardless of which variables hold them
Although we have various type annotations in the language now, they are
all just restrictions on the types of value a variable can hold; they
don't change the behaviour of that value. With this proposal, these two
function would potentially do different things when given the exact same
argument:
function a(FooInterface $arg) { $arg->doSomething(namedparam: 42); }
function b(BarInterface $arg) { $arg->doSomething(namedparam: 42); }
Static typing of that sort is a useful feature of other languages, and
there are people who'd love to see PHP go that way, but it's not
something we should bolt on in a hurry just to solve an issue with named
parameters.
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
Good point about the static typing!
Hi Andreas,
- Calls with named arguments can only happen on:
- explicitly named functions (e.g. no
call_user_func()
).- constructor calls with an explicitly named class.
- object methods, if the object variable is type-hinted or a type is
known at compile time.- Named arguments in calls are converted to number-indexed arguments at
compile time.- Parameter name lookup is done based on the type-hinted class or
interface. Parameter names on the actual object are ignored.While this is an interesting concept in general, it introduces a much
larger change to the semantics of the language than seems justified for
this particular problem - it would effectively require introducing an
element of "static typing" into the language.By "static typing", I mean this:
variables have an intrinsic type, and the same value can behave
differently depending on the type of variable that holds itWhich could be contrasted with "dynamic typing" like this:
values have an intrinsic type, and operations will be selected based
on those values, regardless of which variables hold themAlthough we have various type annotations in the language now, they are
all just restrictions on the types of value a variable can hold; they
don't change the behaviour of that value. With this proposal, these two
function would potentially do different things when given the exact same
argument:function a(FooInterface $arg) { $arg->doSomething(namedparam: 42); }
function b(BarInterface $arg) { $arg->doSomething(namedparam: 42); }
It would be an edge case, if both of them are valid but with
swapped parameter names.
In the more common cases, one of them would simply be broken.
But your point is still correct.
I would argue that this is still better than the behavior with the current
RFC:
The developer who implements the function a or b only knows the parameter
names as in FooInterface or BarInterface.
They know nothing about the actual class of the object passed in as $arg.
A name lookup based on the known interface is closer to what the developer
wants, and is guaranteed to work for all implementations of the interface.
The main inheritance contract for methods is still based on parameter order:
E.g.
interface I {
function foo(A $x, B $y);
}
interface J extends I {
function foo(A $y, B $x);
}
The parameter names can be swapped, but the types have to remain in order.
Static typing of that sort is a useful feature of other languages, and
there are people who'd love to see PHP go that way,
Count me in :)
but it's not
something we should bolt on in a hurry just to solve an issue with named
parameters.
You have a point.
It would not be a full-blown static typing, but at least it has the smell
of it.
The parameter name lookup would be based on the variable itself, instead of
the value.
As mentioned, there could be other ways to determine the version of the
method that should be used for parameter name lookup.
The options I can come up with atm would make the code more verbose, and/or
look awkward, and probably already clash with existing language features.
But perhaps there are better ways.
Either in the call itself:
$x->{FooInterface::doSomething}(namedparam: 42);
FooInterface::doSomething::invoke($x, namedparam: 42);
Or through a declaration in the file:
use \Acme\FooInterface::*();
$x->doSomething()
just to solve an issue with named
parameters.
I still think the current RFC is deeply flawed and should not have been
accepted in its current form.
It adds uncertainty and fragility to the language.
The Liskov substitution principle was something we could rely on,
guaranteed natively by the language. But with named parameters it is not.
I saw the explanations in the RFC about inheritance, but I don't find them
convincing.
But I am not a voting member and also I did not pay attention when this
discussion was happening.
And I am just one person, I don't want to make more than one person's worth
of drama.
Perhaps we will see people mostly use this for constructor or static calls,
and avoid it for polymorphic method calls.
For these cases it seems like a useful feature.
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]--
To unsubscribe, visit: https://www.php.net/unsub.php
On Fri, 24 Jul 2020 at 12:12, Chris Riley <t.carnage@gmail.com
mailto:t.carnage@gmail.com> wrote:
The named parameters RFC has been accepted, despite significant
objections
from maintainers of larger OSS projects
Do you have a reference for which "larger OSS projects" you are
referring to? I don't remember any being named in the previous
discussion, but I may well have missed it.
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.
To reiterate a point I mentioned a couple of days ago, library authors
having to define what constitutes a BC break is definitely not a new
thing. The most obvious example in PHP is that we don't have any package
visibility enforced by the language, so it is entirely commonplace for a
library to have entire classes which are considered implementation
details and not for direct use.
More subtly, any behaviour change can technically be considered a BC
break, and nearly all of those changes are completely unenforceable at
the language level; compatibility is always defined by documentation,
not just code.
I sympathise with people who don't want their library used with named
parameters, or want to choose the names more carefully first, but the
overhead for most projects is adding one line to a README file saying
so. The PHP manual could equally point out the risks of using the
feature with third-party code.
More pressing a point is that the current implementation breaks object
polymorphism.
Although seemingly separate, this can be seen as an extension of the
previous point: if something isn't designed to be used with named
parameters, they should be used with care.
It was also discussed in detail before the vote, and is the subject of
two entire sections of the RFC: one detailing the selected behaviour
https://wiki.php.net/rfc/named_params#parameter_name_changes_during_inheritance
and another detailing the rejected alternatives:
https://wiki.php.net/rfc/named_params#to_parameter_name_changes_during_inheritance
as well as linking to a survey of how other languages approach the
problem: https://externals.io/message/109549#109581
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.
This would be a useful extension of the feature, and with the right
syntax (e.g. Benjamin's suggestion of an attribute) could be added in
8.1, just as scalar types and return types where extended with nullable
types and void returns in 7.1.
The second option would be to use this syntax to make named
parameters in
userland code explicitly opt in.
As others have pointed out, this was explicitly discussed in the run-up
to the original RFC, and anyone who wanted opt-in named parameters could
have voted No to the version Nikita put to the vote. Assuming all the
same people vote, it would need 32 people who voted Yes to the current
proposal to change their minds and back this alternative.
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)
The big disadvantage that persuaded me against this approach is that it
would mean code cannot support both named parameters and PHP 7.x. Since
named parameters are likely to be most useful in shared libraries, and
those libraries are likely to support a range of PHP versions, this
means users would have to wait for:
- the library to drop support for PHP 7
- THEN the library maintainer to add named parameters (likely to be
alongside other breaking changes) - THEN the user's application to be compatible with that version of the
library
While a long lead-time for new features is sometimes necessary, the
alternative here doesn't seem bad enough to justify this kind of delay.
I've never written any code in swift, however having quickly read the
documentation I think that my proposal is almost identical to swift
argument labels if the first option is chosen.
Swift's argument labels are actually only superficially "named
parameters", and come from a completely different background, as I
explained here: https://externals.io/message/110004#110025 They don't
make a particularly good comparison for PHP.
Regards,
Rowan Tommins
[IMSoP]
Hi all,
Thanks for the feedback so far. In light of the feedback received both here
and privately, I've made 3 changes to the RFC document:
-
The original option 1, allowing renaming parameters but not requiring an
explicit opt in to enable them to be called by name has been dropped. The
proposal is now only for explicit opt in parameters with renaming as a
possibility. The reasoning for this, is that although I included option 1
as I thought it might be more likely to be accepted; many people pointed
out that we are very close to the cutoff date for PHP 8.0 and that
implementing such a change would likely be too big to get done in time.
Option 1 would be possible to include in PHP 8.1 as it doesn't break BC,
this means that the proposal can be brought back targeting 8.1 should
option 2 not be accepted. -
With respect to the feature freeze date, I've added a possible strategy
to deal with a staged implementation, should the release managers not feel
comfortable including the full feature at this late stage. -
I have documented the main objections to the RFC on the RFC itself and
included my rebuttals; should anyone feel I've not represented their point
fairly let me know and I'll update.
Regards,
Chris
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.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. egfunction 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 Chris Riley,
I agree with Rowan Tommin's arguments in https://externals.io/message/111161#111179 - I wanted named parameters by default.
Miscellaneous comments:
-
https://wiki.php.net/rfc/renamed_parameters should be moved to "In Discussion" on https://wiki.php.net/rfc/
-
I think that the RFC title should really mention "Making named parameters opt-in",
since that part of the RFC has the largest impact.
(e.g. "Renamed parameters and making named parameters opt-in").
(The RFC URL should not be changed) -
For your examples, I assume you mean "Class Bar extends Foo {" instead of "class Bar {"
-
"Error: cannot call parameter $externalName by name." seems incorrect,
I assume "cannot call callBar() with parameter $externalName by name" or something along those lines was intended -
https://wiki.php.net/rfc/renamed_parameters#attributes still mentions "option 1" and "option 2", but those were removed from the current version of the proposal, making this confusing
-
How will this RFC expect internal functions such as
substr_compare()
or internal methods such asArrayObject::__construct()
included in php-src?What about PECLs - will existing function declaration macros be treated as opted out of or into named parameters?
-
This is missing some details on how reflection and backtrace generation will be affected.
I assumeReflectionParameter->getInternalName(): string
,ReflectionParameter->getExternalName(): ?string
, etc. will need to be added.
getTrace() and getTraceAsString() -
Renaming parameters offers only a small performance benefit and I don't think it would get used very frequently.
It's possible to add$newName = $oldName; unset($oldName);
(or in most cases, to update the method implementation body). -
Are declarations such as
function test($:publicName, $nonPublicName) {}
an error?I'd personally prefer https://wiki.php.net/rfc/named_params#positional-only_and_named-only_parameters to allow API designers to explicitly opt out of named parameters.
-
As Rowin Tommins had said, "maintainers of larger OSS projects" is a broad claim and could be clarified
(e.g. what fraction of maintainers? Were there polls/discussion threads of maintainers/owners of OSS projects?)
Since there are strong objections from some maintainers of supporting always-enabled named parameters,
I'd think a useful alternative would be to add a positional-only parameter syntax instead in 8.0, similar to what Python,
so that maintainers that want to avoid supporting named parameters in their API can clearly express that in a release requiring ^8.0.
This is using syntax for https://www.python.org/dev/peps/pep-0570/#history-of-positional-only-parameter-semantics-in-python for clarity,
but obviously other syntax might suit PHP better.
(mentioned in https://wiki.php.net/rfc/named_params#positional-only_and_named-only_parameters)
function test(int $x, /, string $y) {}
test(x: 1, y: "test"); // Error: test() does not support being called with parameter $x by name
test(1, y: "test"); // allowed
function test_varargs(...$args, /) {}
test_varargs(x: 1); // Error: test_varargs() does not support being called with named variable argument $x in ...$args
test_varargs(...['x' => 1]); // Error: test_varargs() does not support being called with named variable argument $x in ...$args
There may be concerns such as whether /
can be added when overriding,
or in forbidding using ...$newArgs, /
to override ...$originalArgs
but since parameter renaming was already allowed in the Named Arguments RFC this should not be a new issue.
Regards,
- Tyson
Hi all,
Thanks for the feedback so far. In light of the feedback received both here
and privately, I've made 3 changes to the RFC document:
- The original option 1, allowing renaming parameters but not requiring an
explicit opt in to enable them to be called by name has been dropped. The
proposal is now only for explicit opt in parameters with renaming as a
possibility. The reasoning for this, is that although I included option 1
as I thought it might be more likely to be accepted; many people pointed
out that we are very close to the cutoff date for PHP 8.0 and that
implementing such a change would likely be too big to get done in time.
Option 1 would be possible to include in PHP 8.1 as it doesn't break BC,
this means that the proposal can be brought back targeting 8.1 should
option 2 not be accepted
Can you clarify if opt-in would only be the behavior on userland functions,
or if all internal functions would also change to opt-in?
If no, then the inconsistency must be explained.
if yes then the next steps for each internal API to decide on allowing
named params or not needs to be explained
Both approaches lead to a lot of problems down the road that were nicely
circumvented by auto-optin of all functions.
Implementation wise, with external name, you have only one name on the call
site. That means if you decide to rename an argument,
then you cannot support both the old and the new name for one major release
cycle to allow your users to upgrade smoothly.
As such it is my opinion that this is an inferior approach to having an
alias that allows declaring a second name.
Have you given an E_NOTICE/E_WARNING a thought? A user of a library could
then overwrite a library authors "with" to disallow named parameters.
Can you add an example how the MessageHandler problem would look like with
your proposal? Is the external name inherited? Is it forced to inherit? Can
it be overwritten?
- With respect to the feature freeze date, I've added a possible strategy
to deal with a staged implementation, should the release managers not feel
comfortable including the full feature at this late stage.
Can you update the Proposed Voting Choices section with the two questions
for the staged implementation? or the one question combining them both? The
wording is going to be signifcant for further discussion.
- I have documented the main objections to the RFC on the RFC itself and
included my rebuttals; should anyone feel I've not represented their point
fairly let me know and I'll update.
Your "objections" section mentions the inheritance / polymorphism part
being buried/hidden in the RFC, but its a section on its own
https://wiki.php.net/rfc/named_params#parameter_name_changes_during_inheritance
and Nikita sent several mails to the list about this topic, asking for
specific feedback about this outstanding issue alone.
The main change in your RFC from explicitly enabled for all userland and
internal functions to an opt-in approach for userland functions was also
discussed in depth.
Similar approaches to your suggestions were also mentioned again in the RFC
prominently under "Alternatives", overruled by the voted upon
implementation that got 76% acceptance.
Regards,
Chris
At this point I would much prefer to discuss amendments within the current
behavior and not against it.
My counter-proposal is still to have two, potentially three attributes:
- @@NameAlias to define a second name/alias for a parameter. Would help
solve both polymorphic name changes and refactoring of names. - @@PositionalArgumentsOnly to define on a function or class, throwing an
exception if used with named arguments. This only slightly makes the use
case of named arguments slower.
Maybe the reverse with @@NamedArgumentsOnly - however checking for that
would probably slightly make all positional calls slower, which will
probably stay the primary way of calling functions. Trade offs are unclear
here.
I know attributes "feel" wrong here, being a new feature and not been used
for anything yet in the language. But attributes have the benefit of not
introducing new keywords or syntax to the language and are the right tool
to "re-configure" a feature from its primary behavior. Use of attributes
would also keep open future changes (by introducing new attributes or
arguments to the existing ones) leaving our options open instead of locking
them down further.
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.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. egfunction 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 Chris,
Thanks for the feedback so far. In light of the feedback received both here
and privately, I've made 3 changes to the RFC document
Firstly, a reminder of the guideline in the RFC howto that the link to
the RFC should be included in replies, which is particularly relevant
when announcing changes to the text. For others trying to find it, it is
here: https://wiki.php.net/rfc/renamed_parameters
Secondly, regardless of the merits of your proposal in itself, I think
an RFC in this position should explicitly state why it is proposing to
re-visit an accepted feature. I can think of a handful of possible
reasons, but none seem to apply:
- If new concerns have come to light which are likely to change the
opinion of those who voted Yes. This is not the case for the concerns in
your introduction. - If the RFC passed only by a narrow margin, or a low turnout, and this
version is expected to gain a larger majority. The RFC passed with a
ratio of 3:1, with 75 votes cast [1]. - If the RFC discussion was rushed, so that people did not have adequate
time to understand the proposal and discuss its implications. The RFC
was informally resurrected at the start of April [2] and formally at the
start of May [3] and saw plenty of discussion. - If there is evidence that people voted Yes despite reservations that
this proposal resolves. No evidence is presented of this, and the only
message of that sort in the voting thread expressed reservations
unrelated to this proposal. [4] - If there is evidence that (a significant number of) people who voted
Yes have now changed their minds having re-considered the implications.
No evidence is presented of this.
As Benjamin says, the pragmatic way forward would be to discuss
enhancements on top of the accepted feature, rather than last-minute
alternatives to it.
[1] This appears to be the second highest turnout after Scalar Type
Declarations, according to https://php-rfc-watch.beberlei.de/
[2] https://externals.io/message/109549
[3] https://externals.io/message/110004
[4] https://externals.io/message/110910#110961
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
Hi internals,
Continuing on my response in https://externals.io/message/111161#111192 , and considering ways to enhance named arguments without a BC break
(while minimizing the impact on application/library authors that wish for their libraries not to be used with named parameters)
I was considering setting up a short straw poll on the wiki for a week with two questions, open for a week:
-
Whether voters consider it appropriate to add amendments/enhancements to named parameters (in general) in php 8.0 past the feature freeze. (Both/Backward Compatible Enhancements Only/No)
(yes if interested in any of the alternatives proposed in https://externals.io/message/111161)I'd recognize that named parameters are potentially a large change to what is considered the public API of a project,
so I'd think continuing to add enhancements would be worthwhile, but I'd like to know where others stand on this.
(e.g. if any proposals I made should be postponed to 8.1)I'd also think that implementing a backwards incompatible change after the feature freeze (in terms of impact on code targeting 8.0 alphas at the time of the feature freeze)
would be a bad precedent. -
Interest in adding support for positional-only arguments in 8.0 or 8.1 (3 options: 8.0, 8.1, or no)
(e.g. with a symbol such as
/
to indicate that parameters or variadic parameters prior to the symbol are positional-only)I'd consider positional-only arguments useful in some cases, such as where the names would always be confusing,
(or automatically generated code)-
function my_merge(string $firstArg, ...string $otherArgs, /) { }
This also provides an easy way for user-defined code to add restrictions similar to whatarray_merge()
already has. -
function my_pow($x, $y, $z = null, /,) {}
- `function autoGeneratedCode($arg1, $arg2, /) {}
Other syntaxes are possible, such as using attributes
(I would find 5 attributes rather verbose if there were 5 positional-only parameters),
or keywords such as__END_POSITIONAL_PARAMETERS
.
Nothing stood out as a good option (e.g._
,...
,%
seem meaningless,*
would be the opposite of python,#
can't be used),
and I've only seen markers for the end of positional-only parameters in python after a quick check, so at least some users would find/
easier to learn/remember. -
On an unrelated note,
- A few people had suggested adding a line to a README indicating that named parameters aren't supported.
An idea I had was to standardize on a machine-readable file format (e.g. ".php_analysis_config.json") that IDEs/analyzers may choose to support.
It might have JSON entries such as"supports_named_parameters": false
to indicate that code (e.g. src/main.php) using files in that directory (e.g. vendor/a/b/ with vendor/a/b/.php_analysis_config.json)
should not invoke functions/methods in vendor/a/b/ with named parameters,
because there is no guarantee the names will remain the same.
(TOML or ini settings might be more readable, but a complicated format requires extra dependencies and ini files won't support arrays if future settings get added)
- I can't think of many other settings I'd want there that aren't covered by composer.json, editorconfig, or other means.
Maybe less importantly"supports_classes_being_extended": bool
- Alternately, it might be possible to put it in "extra" of composer.json,
but some projects/libraries don't use composer.json (e.g. a project has both vendor/ and third-party/) - I'm not aware of similar indicators for python for named arguments, so there might not be much interest in such a proposal. Then again, I think python had named arguments for much longer.
- Another attribute idea I had was
<<ConsistentNamedParameters>>
on a class/method,
to make PHP enforce that method overrides other than __construct must
have the same names in the same positions and not lead to errors when valid named arguments are passed to subclasses,
but I don't plan to propose that any earlier than 8.1
(e.g. for classes that have calls such as$this->method(someFlag: true);
)
Thanks,
- Tyson
Hi all,
RFC link: https://wiki.php.net/rfc/renamed_parameters
I have spent the weekend working on a final revision for this RFC to
address several of the points brought up. Specifically:
- Cut down the scope of the RFC to only focus on delivering an opt in to
named parameters, with the renaming ability explicitly pushed into future
scope as opposed to leaving it to the RM discretion. This will allow a
fuller discussion on how best to support renaming going forward, be it
using my proposed syntax or using attributes. - Focused in on the technical issues as opposed to subjective arguments
for/against. - Added additional example of the polymorphism problem when it comes to the
behaviour of variadics, which didn't seem to come up in the original RFC. - Added resolution on dealing with the PHP standard library, as this is an
enhancement to the original named parameters RFC, this RFC proposes to opt
in the PHP standard library. There are a couple of minor changes to
behaviour for classes which extend built ins to make upgrading smoother. - Clarified changes to reflection parameter
- Added alternative implementation option using attributes which will be
the subject of an additional voting option for those who would prefer to go
down this route.
I think the RFC now represents a concrete problem and solution suitable for
voting on, but I'm going to leave discussion open for a few days in case
anyone has any queries on the revisions.
Regards,
Chris
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.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. egfunction 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
Hey Chris,
thanks for the RFC but I'd like to remind you that we are already past the
feature freeze. Moreover, it seems that you don't have an actual
implementation as well.
Best regards,
Benas
Hi all,
RFC link: https://wiki.php.net/rfc/renamed_parameters
I have spent the weekend working on a final revision for this RFC to
address several of the points brought up. Specifically:
- Cut down the scope of the RFC to only focus on delivering an opt in to
named parameters, with the renaming ability explicitly pushed into future
scope as opposed to leaving it to the RM discretion. This will allow a
fuller discussion on how best to support renaming going forward, be it
using my proposed syntax or using attributes.- Focused in on the technical issues as opposed to subjective arguments
for/against.- Added additional example of the polymorphism problem when it comes to the
behaviour of variadics, which didn't seem to come up in the original RFC.- Added resolution on dealing with the PHP standard library, as this is an
enhancement to the original named parameters RFC, this RFC proposes to opt
in the PHP standard library. There are a couple of minor changes to
behaviour for classes which extend built ins to make upgrading smoother.- Clarified changes to reflection parameter
- Added alternative implementation option using attributes which will be
the subject of an additional voting option for those who would prefer to go
down this route.I think the RFC now represents a concrete problem and solution suitable for
voting on, but I'm going to leave discussion open for a few days in case
anyone has any queries on the revisions.Regards,
ChrisHi 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.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. egfunction 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
After sending out the email, I found out that I replied to the wrong email,
nevermind... Sorry about that!
Best regards,
Benas
Hey Chris,
thanks for the RFC but I'd like to remind you that we are already past the
feature freeze. Moreover, it seems that you don't have an actual
implementation as well.Best regards,
BenasHi all,
RFC link: https://wiki.php.net/rfc/renamed_parameters
I have spent the weekend working on a final revision for this RFC to
address several of the points brought up. Specifically:
- Cut down the scope of the RFC to only focus on delivering an opt in to
named parameters, with the renaming ability explicitly pushed into future
scope as opposed to leaving it to the RM discretion. This will allow a
fuller discussion on how best to support renaming going forward, be it
using my proposed syntax or using attributes.- Focused in on the technical issues as opposed to subjective arguments
for/against.- Added additional example of the polymorphism problem when it comes to
the
behaviour of variadics, which didn't seem to come up in the original RFC.- Added resolution on dealing with the PHP standard library, as this is an
enhancement to the original named parameters RFC, this RFC proposes to opt
in the PHP standard library. There are a couple of minor changes to
behaviour for classes which extend built ins to make upgrading smoother.- Clarified changes to reflection parameter
- Added alternative implementation option using attributes which will be
the subject of an additional voting option for those who would prefer to
go
down this route.I think the RFC now represents a concrete problem and solution suitable
for
voting on, but I'm going to leave discussion open for a few days in case
anyone has any queries on the revisions.Regards,
ChrisHi 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.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. egfunction 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 all,
RFC link: https://wiki.php.net/rfc/renamed_parameters
I have spent the weekend working on a final revision for this RFC to
address several of the points brought up.
My opinion on this RFC remains unchanged:
- It would have been a reasonable alternative proposal to bring to the
list 3 months ago [1] when Nikita formally resurrected his RFC - The problem it highlights would be a suitable reason to vote "No" to
that proposal
But:
- It is effectively a complete replacement for, not a minor amendment
of, the previous RFC - The solution it proposes was discussed on the list at least once but
didn't receive substantial support [2] - It doesn't present any evidence that those who voted Yes to the
previous RFC [3] were missing information, have changed their minds, or
voted for a proposal they thought was non-optimal, in sufficient numbers
to reverse a majority of 39.
It is true that the behaviour of variadic parameters wasn't discussed
very thoroughly, and some concerns with it were raised during voting
[4]. An RFC amending or removing that behaviour would feel like a more
reasonable amendment, since it doesn't change the core feature that has
been overwhelmingly accepted.
[1] https://externals.io/message/110004
[2] https://externals.io/message/109549#109558 (I used :$foo in my
examples rather than $:foo, but it's otherwise an identical proposal I
think)
[3] https://wiki.php.net/rfc/named_params#vote
[4] https://externals.io/message/110910#110961
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]