Hi internals!
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.
Thanks,
Nikita
I like!
My preference on syntax is;
test(:foo => "oof", :bar => "rab");
I don't think;
test("foo" => "oof", "bar" => "rab");
denotes enough emphasis on any part in-particular, and the downsides
of other implementations are mentioned, such as variable names and
collisions with reserved keywords.
Thanks,
Gareth
Hi internals!
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.Thanks,
Nikita
Hi Nikita,
Will it be possible to set the named parameter through using a parameter?
i.e. can you do:
function multipleParamFunction($var1 = null, $var2 = null, $var3 = null,
$var4 = null) {
//...
}
$paramToOverride = 'var3';
testFunction($paramToOverride => 'bar');
which would override 'var3' in the function.
The syntax for setting a named parameter by a parameter clashes with some
of the suggested syntaxes. Even if it isn't going to be possible to support
this currently, it would be a good idea to not use a syntax that prevents
support of this in the future.
cheers
Dan
Hi internals!
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.Thanks,
Nikita
Dan,
That's a good question as well, with the current $var syntax I'm assuming NO.
You're using the $var3 name as a key, not as the $paramToOverride value.
Maybe the collon could be used here?
$paramToOverride = 'var3';
testFunction(:$paramToOverride => 'bar'); // Colon before $ would make
the key :var3 ?
Then again, I like the colon syntax instead of => to assign fn(key:
val) pairs for readability/clearer separation of array syntax, so that
would probably make:
testFunction(:$paramToOverride: 'bar');
As my suggestion and I'm not sure I like it... :x
Regarding variable parameter names; if the syntax was:
function foo( $firstParameter ) { ... }
foo( $firstParameter=> 'foo' );
Then the double-dollar syntax would seem the obvious choice to me:
function foo( $firstParameter ) { ... }
$param = 'firstParameter';
foo( $$param => 'whatever' );
Which is no less readable than anywhere else the double-dollar is
allowed... :-p
--G
George Bond wrote:
Then the double-dollar syntax would seem the obvious choice to me:
foo( $$param => 'whatever' );
Which is no less readable than anywhere else the double-dollar is
allowed... :-p
For the simple case I agree having double $$ signs is not that bad, but it
would get nasty for anything other than a simple variable. e.g. if the
param name was in an array:
$searchKeys[] = 'firstParameter'
$searchValues[] = 25;
foo( ${$searchKeys[0]} => $searchValues[0] );
which is definitely less legible than:
foo( $searchKeys[0] => $searchValues[0] );
cheers
Dan
On Fri, Sep 6, 2013 at 6:44 PM, George Bond
happy.melon.wiki+gb@gmail.comwrote:
Regarding variable parameter names; if the syntax was:
function foo( $firstParameter ) { ... }
foo( $firstParameter=> 'foo' );Then the double-dollar syntax would seem the obvious choice to me:
function foo( $firstParameter ) { ... }
$param = 'firstParameter';
foo( $$param => 'whatever' );Which is no less readable than anywhere else the double-dollar is
allowed... :-p--G
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.
Thanks for proposing this. I haven't looked at the patch yet, but I'm
all for the feature.
My thoughts on your open questions:
Syntax: I suspect this will end up having to go to a vote (classic
bikeshed), but I'm on the func('foo' => 'bar') train. :foo doesn't
make sense in a PHP context (we'd have to implement that across the
language, not just for function calls), : as a key-value separator
would only work if it was also supported in array literals, and =
feels a little wrong for this. I don't really like the unquoted
parameter names so much; it's inconsistent with array literals and
bare words as strings is something that's been discouraged for a long
time.
Variadics/splat: collecting both named and positional arguments into
one array seems reasonable to me. I think the main use case there
would be option parameters, which you'd have to validate anyway, so
positional parameters would be dealt with at that point — I don't see
separate arrays as conferring any great advantage in terms of
validating parameters, and it's no simpler conceptually.
call_user_func_array: for consistency, we might want to consider
adding an analogue function that deals with named parameters, even
though it would work via $callable(...$kwargs).
Contracts: I agree with you, basically — it would have to be an
E_STRICT
or thereabouts, with the possibility of revisiting come a
hypothetical PHP 6.
Adam
2013/9/6 Adam Harvey aharvey@php.net
Variadics/splat: collecting both named and positional arguments into
one array seems reasonable to me. I think the main use case there
would be option parameters, which you'd have to validate anyway, so
positional parameters would be dealt with at that point — I don't see
separate arrays as conferring any great advantage in terms of
validating parameters, and it's no simpler conceptually.
There is a small drawback. Suppose this code:
function foo( $bar = 0 , ...$args ){}
foo( bart => 3 ); // misspelled name
According to the RFC, any unknown argument name will fall into the $args
array, making the above code valid. As this cannot be verified statically,
it is a possible source of bugs.
Lazare INEPOLOGLOU
Ingénieur Logiciel
Hi Nikita
First of all, thanks for your proposal.
I'd like to make some comments, see below.
-----Original Message-----
From: Lazare Inepologlou [mailto:linepogl@gmail.com]
Sent: Friday, September 06, 2013 7:55 PM
To: Adam Harvey
Cc: Nikita Popov; PHP internals
Subject: Re: [PHP-DEV] [RFC] Named parameters2013/9/6 Adam Harvey aharvey@php.net
Variadics/splat: collecting both named and positional arguments into
one array seems reasonable to me. I think the main use case there
would be option parameters, which you'd have to validate anyway, so
positional parameters would be dealt with at that point — I don't see
separate arrays as conferring any great advantage in terms of
validating parameters, and it's no simpler conceptually.There is a small drawback. Suppose this code:
function foo( $bar = 0 , ...$args ){}
foo( bart => 3 ); // misspelled nameAccording to the RFC, any unknown argument name will fall into the $args
array, making the above code valid. As this cannot be verified statically, it is a
possible source of bugs.Lazare INEPOLOGLOU
Ingénieur Logiciel
I agree with Lazare, it seems wrong to me to mix *args and **kwargs and put everything in one argument. Especially because this will hide bugs for sure, but also because if I want to use *args then I do not want necessarily support **kwargs as well (as mentioned in your cons).
Btw did I miss something? I could not read anything about **kwargs in your variadics RFC. Because you do not want to introduce it together with *args?
I now assume you do not want to introduce **kwargs and handle everything with *args. That's why you came up with the idea to put everything in *args, right?
I'd like to outline an example where **kwargs would be very useful. Sorry, somehow off-topic but that's just because this RFC refers to other RFCs which are not yet accepted. I think it's not a good idea to start mixing several RFC. It almost seems like variadics, argument unpacking and named parameters can only coexist together. But anyway... now I go the same way :P
**kwargs is very useful if you want to have a type for *args and some options for **kwargs
Let's say I have defined a function which renders an arbitrary number of contact details (one contact per row) and you want to be able to pass in some additional html attributes which shall be applied for each <tr>.
function renderAsTable(array $htmlAttributes, Contact ...$args){}
renderAsTable(['class' => 'someClass', 'validate'=>'true'], $contact1, $contact2);
vs.
function renderAsTable(Contact ...$args, =>...$htmlAttributes){} // =>... should stand for **kwargs, I do not like this syntax but nothing else came into my mind right now
renderAsTable($contact1, $contact2, 'class' => 'someClass', 'validate'=>'true');
I know, the first syntax doesn't seem to be too bad yet (apart from ['class' => 'someClass', 'validate'=>'true'] is almost looking like named arguments, maybe => isn't a good choice and we should prefer something else?) but consider when you combine it with argument unpacking
renderAsTable(array_merge($arr, ['class' => 'someClass', 'validate'=>'true']), ], $contact1, $contact2);
vs.
renderAsTable($contact1, $contact2, 'class' => 'someClass', 'validate'=>'true', ...$arr);
I prefer the second version and I guess you agree that variadics shall be introduced to reduce array_merge. Thus it seems logical to me to introduce **kwargs as well and therefore I would not mix them and put everything only in one argument. Otherwise you will have problems to introduce **kwargs later on.
You could argue one could write the second version and handle everything in the function. But I am pretty sure that no one wants to have such an overhead either. Something like:
function renderAsTable(...$args){
$htmlAttributes = []
$contacts = []
foreach($args as $key => $value){
if($value instanceof Contact){
$contacts[] = $value;
} else {
$htmlAttributes[] = $value;
}
}
//now do your stuff
}
You could also argue, that one just need to write the function in a different way:
function renderAsTable(array $contacts, ...$htmlAttributes){}
Might work as a workaround in this case, but then I lose the ability to have a type checked array ;-)
Cheers,
Robert
+1 to named params. Please please please. :)
=> is my vote for syntax. Makes sense. Doesn't make sense to introduce another way to express something we've been used to for years with key => value, and is it that important to save one character per assignment?
Hi internals!
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.Thanks,
Nikita
Hi,
Hi internals!
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.
From the explanation it sounds like there shouldn't be a high cost, but
as fcalls are a key operation and already quite slow I wonder if you
could share some benchmarks. (non-debug-non-tsrm-build)
A good start might be Zend/bench.php. And I understand this is not the
final patch but good to have the order of magnitude.
johannes
On Fri, Sep 6, 2013 at 8:01 PM, Johannes Schlüter johannes@schlueters.dewrote:
From the explanation it sounds like there shouldn't be a high cost, but
as fcalls are a key operation and already quite slow I wonder if you
could share some benchmarks. (non-debug-non-tsrm-build)A good start might be Zend/bench.php. And I understand this is not the
final patch but good to have the order of magnitude.
I didn't see any obvious regressions from Zend/bench.php and this is also
what I would expect: The parts relating to named arguments are hidden
behind optype-specialization of the send opcodes, so those shouldn't affect
perf. There is also a bit extra code in do_fcall_common to handle passing
of additional unknown named params, but that's also just two branches in a
large mix of other code. So it really "shouldn't" impact performance and
judging from Zend/bench.php it doesn't.
I also did a very quick test how a normal call compares to one using named
params. Right now the latter is about 25% slower. But I'm pretty sure this
number can be improved a good bit, e.g. I'm not yet making use of
CACHED_PTR to store the argument number of the parameter.
Nikita
Hi Nikita,
If named parameters are introduced, signature validation should include
parameter names. Throwing a fatal error (for the interface/class
combination)
would break backwards compatibility though. We could use some lower error
type...
Would it be possible to set the error level through an ini setting? Or
disable it entirely?
People who are writing new code that is aware of named parameters should
want a fatal error for any coding mistake that violates the contract.
People who are supporting legacy code that doesn't use named parameters
should be able to upgrade to the latest version of PHP without having to
refactor an entire code base or suppressing huge numbers of compiler
warnings.
cheers
Dan
Hi internals!
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.Thanks,
Nikita
If named parameters are introduced, signature validation should include
parameter names. Throwing a fatal error (for the interface/class
combination)
would break backwards compatibility though. We could use some lower error
type...Would it be possible to set the error level through an ini setting? Or
disable it entirely?
I've said this before, but to reiterate it: I'd be a huge -1 on
anything that involves configurable language behaviour. It's a support
nightmare, and I'm glad those days are now mostly over.
People who are writing new code that is aware of named parameters should
want a fatal error for any coding mistake that violates the contract.
I'd say the odds are that those sorts of users are going to be writing
code that is required to be notice/strict clean anyway — that's
certainly been true everywhere I've worked that's had a "modern"
codebase.
Adam
Hi Adam
I'd say the odds are that those sorts of users are going to be writing
code that is required to be notice/strict clean anyway — that's
certainly been true everywhere I've worked that's had a "modern"
codebase.
Yes, so say you have a team that:
- currently has a code base that is notice/strict clean
- wants to move to PHP 5.x which has named parameters
- have code which changes the param name in extends/implements
Unless they rewrite their code, they wouldn't be able to upgrade next
version of PHP without losing their strict/notice cleaness. So how would
you suggest they upgrade to the version of PHP with named parameters?
Also I'm not sure that having which error level is used actually changes
the behaviour of the language in a meaningful way. It only suppresses a
particular warning message, which can be suppressed anyway with
error_reporting(0).
cheers
Dan
If named parameters are introduced, signature validation should include
parameter names. Throwing a fatal error (for the interface/class
combination)
would break backwards compatibility though. We could use some lower
error
type...Would it be possible to set the error level through an ini setting? Or
disable it entirely?I've said this before, but to reiterate it: I'd be a huge -1 on
anything that involves configurable language behaviour. It's a support
nightmare, and I'm glad those days are now mostly over.People who are writing new code that is aware of named parameters should
want a fatal error for any coding mistake that violates the contract.I'd say the odds are that those sorts of users are going to be writing
code that is required to be notice/strict clean anyway — that's
certainly been true everywhere I've worked that's had a "modern"
codebase.Adam
I'd say the odds are that those sorts of users are going to be writing
code that is required to be notice/strict clean anyway — that's
certainly been true everywhere I've worked that's had a "modern"
codebase.Yes, so say you have a team that:
- currently has a code base that is notice/strict clean
- wants to move to PHP 5.x which has named parameters
- have code which changes the param name in extends/implements
Unless they rewrite their code, they wouldn't be able to upgrade next
version of PHP without losing their strict/notice cleaness. So how would you
suggest they upgrade to the version of PHP with named parameters?
At the risk of being glib, by cleaning up their parameter names. A
team that's testing a PHP upgrade is likely capable of that, and the
strict notices would give them the needed feedback in the early stages
of testing. That's hardly a rewrite.
Also I'm not sure that having which error level is used actually changes the
behaviour of the language in a meaningful way. It only suppresses a
particular warning message, which can be suppressed anyway with
error_reporting(0).
I don't really care which level actually gets used (it could be
anywhere from E_STRICT
to E_WARNING
from where I sit), but I don't
think the error reporting for a particular feature should ever be
controllable separately from PHP's global error reporting. These sorts
of warnings are there to promote better practice.
Adam
-----Original Message-----
From: adam@adamharvey.name [mailto:adam@adamharvey.name] On
Behalf Of Adam Harvey
Sent: Friday, September 06, 2013 10:11 PM
To: Dan Ackroyd
Cc: Nikita Popov; PHP internals
Subject: Re: [PHP-DEV] [RFC] Named parametersI'd say the odds are that those sorts of users are going to be
writingcode that is required to be notice/strict clean anyway — that's
certainly been true everywhere I've worked that's had a "modern"
codebase.Yes, so say you have a team that:
- currently has a code base that is notice/strict clean
- wants to move to PHP 5.x which has named parameters
- have code which changes the param name in extends/implements
Unless they rewrite their code, they wouldn't be able to upgrade next
version of PHP without losing their strict/notice cleaness. So how
would you suggest they upgrade to the version of PHP with named
parameters?At the risk of being glib, by cleaning up their parameter names. A team that's
testing a PHP upgrade is likely capable of that, and the strict notices would
give them the needed feedback in the early stages of testing. That's hardly a
rewrite.Also I'm not sure that having which error level is used actually
changes the behaviour of the language in a meaningful way. It only
suppresses a particular warning message, which can be suppressed
anyway with error_reporting(0).I don't really care which level actually gets used (it could be anywhere from
E_STRICT
toE_WARNING
from where I sit), but I don't think the error
reporting for a particular feature should ever be controllable separately from
PHP's global error reporting. These sorts of warnings are there to promote
better practice.Adam
Heya,
I do not like the check at all and after writing a few lines for this email, deleting, writing again etc. I have to conclude, named parameters do not really suit to PHP if such a check is really implemented. -1 in this case
I understand that you have to make this check with your current solution. I did not have a look at the implementation though, but I guess this consistency of parameter names is needed since you do not know what type a variable has. This check of the whole class hierarchy certainly slows down also use cases where named parameters aren't used at all. But that's not even my biggest concern.
Following an example to outline why I do not like the check:
interface IExecutor{
function execute(callable $command);
}
class SaveExecutor implements IExecutor{
public function execute(callable $saveCommand){}
}
function foo(IExecutor $bar){
$bar->execute(command=>function(){});
}
In the function foo I use IExecutor as contract, I do not really care what the implementation is and thus I use command as named parameter. IMO that should be enough and I as a developer of the class SaveExecutor can choose whatever I like as parameter name to improve the readability.
Sure, you could say the renaming above isn't really necessary and I could have used just $command instead of $saveCommand, but what if you use a third library and they named their parameters in the following way:
interface ICustomer{
function createRelation($custId, $adrId, $main=false);
}
Maybe you are able to guess that they expect an customer id, an address id and $main stands for whether this address is the main address of the customer or not.
Right now I am not really too bothered about this bad naming of the parameters since I can use different ones in my implementation.
Another use case could be, that one has to comply with some code guidelines which might claim, one needs to write a prefix before the parameter name if it is a scalar type. Something like $intCustId (puke)
Without the check I can save the hassle to write a wrapper around the library to improve readability or to comply with some code guidelines (there are further use cases I suppose).
I agree that if we introduce named parameters the parameter name has to be part of the contract, but as I said, I do not like the constraint and overkill it would add up. Personally I use named parameters very seldom and at the moment I would prefer the skipping parameters RFC. I see more drawbacks than benefits of named parameters in a type-unsafe language such as PHP.
Cheers,
Robert
-----Original Message-----
From: Robert Stoll [mailto:rstoll@tutteli.ch]
Sent: Sunday, September 08, 2013 12:36 AM
To: 'Adam Harvey'; 'Dan Ackroyd'
Cc: 'Nikita Popov'; 'PHP internals'
Subject: RE: [PHP-DEV] [RFC] Named parameters-----Original Message-----
From: adam@adamharvey.name [mailto:adam@adamharvey.name] On
Behalf Of
Adam Harvey
Sent: Friday, September 06, 2013 10:11 PM
To: Dan Ackroyd
Cc: Nikita Popov; PHP internals
Subject: Re: [PHP-DEV] [RFC] Named parametersOn 6 September 2013 13:01, Dan Ackroyd danack@basereality.com
wrote:I'd say the odds are that those sorts of users are going to be
writingcode that is required to be notice/strict clean anyway — that's
certainly been true everywhere I've worked that's had a "modern"
codebase.Yes, so say you have a team that:
- currently has a code base that is notice/strict clean
- wants to move to PHP 5.x which has named parameters
- have code which changes the param name in extends/implements
Unless they rewrite their code, they wouldn't be able to upgrade
next version of PHP without losing their strict/notice cleaness. So
how would you suggest they upgrade to the version of PHP with named
parameters?At the risk of being glib, by cleaning up their parameter names. A
team that's testing a PHP upgrade is likely capable of that, and the
strict notices would give them the needed feedback in the early stages
of testing. That's hardly a rewrite.Also I'm not sure that having which error level is used actually
changes the behaviour of the language in a meaningful way. It only
suppresses a particular warning message, which can be suppressed
anyway with error_reporting(0).I don't really care which level actually gets used (it could be
anywhere fromE_STRICT
toE_WARNING
from where I sit), but I don't
think the error reporting for a particular feature should ever be
controllable separately from PHP's global error reporting. These sorts
of warnings are there to promote better practice.Adam
Heya,
I do not like the check at all and after writing a few lines for this email,
deleting, writing again etc. I have to conclude, named parameters do not
really suit to PHP if such a check is really implemented. -1 in this caseI understand that you have to make this check with your current solution. I
did not have a look at the implementation though, but I guess this
consistency of parameter names is needed since you do not know what type
a variable has. This check of the whole class hierarchy certainly slows down
also use cases where named parameters aren't used at all. But that's not
even my biggest concern.Following an example to outline why I do not like the check:
interface IExecutor{
function execute(callable $command); }class SaveExecutor implements IExecutor{
public function execute(callable $saveCommand){} }function foo(IExecutor $bar){
$bar->execute(command=>function(){});
}In the function foo I use IExecutor as contract, I do not really care what the
implementation is and thus I use command as named parameter. IMO that
should be enough and I as a developer of the class SaveExecutor can choose
whatever I like as parameter name to improve the readability.
Sure, you could say the renaming above isn't really necessary and I could
have used just $command instead of $saveCommand, but what if you use a
third library and they named their parameters in the following way:interface ICustomer{
function createRelation($custId, $adrId, $main=false); }Maybe you are able to guess that they expect an customer id, an address id
and $main stands for whether this address is the main address of the
customer or not.
Right now I am not really too bothered about this bad naming of the
parameters since I can use different ones in my implementation.
Another use case could be, that one has to comply with some code
guidelines which might claim, one needs to write a prefix before the
parameter name if it is a scalar type. Something like $intCustId (puke)Without the check I can save the hassle to write a wrapper around the library
to improve readability or to comply with some code guidelines (there are
further use cases I suppose).I agree that if we introduce named parameters the parameter name has to
be part of the contract, but as I said, I do not like the constraint and overkill it
would add up. Personally I use named parameters very seldom and at the
moment I would prefer the skipping parameters RFC. I see more drawbacks
than benefits of named parameters in a type-unsafe language such as PHP.Cheers,
Robert
I have a further reason why this check shouldn't be done and the implementation need to be changed:
namespace some\library {
interface ILogger {
function log($message);
}
}
namespace another\library{
interface ILogger{
function log($msg);
}
}
namespace {
class Logger implements some\library\ILogger, another\library\ILogger{
function log($message){}
}
}
Valid code today, the check would be another BC break.
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.
I feel like this will just encourage more core PHP functions with an
unmanageable number of parameters. Will there be any proposed
guidelines to how future functions will make use of named parameters?
e.g., Will we see native functions with 20 arguments?
What I don't like about named parameters is that if I build a library,
now even my parameter names are unchangeable if I don't want to break
any backward compatibility, since I never know if somebody will decide
to call my single parameter method with named parameters. Are we
prepared to go through every PHP function and make sure the names of
the parameters are set in stone before this feature would go live?
So I'm neutral to this proposal, as I would never purposefully build a
function that is so convoluted that it needs named parameters, but I
understand that's how some people like to write code, and it could be
useful in extreme cases.
--
Matthew Leverton
Matthew Leverton wrote:
What I don't like about named parameters is that if I build a library,
now even my parameter names are unchangeable if I don't want to break
any backward compatibility, since I never know if somebody will decide
to call my single parameter method with named parameters. Are we
prepared to go through every PHP function and make sure the names of
the parameters are set in stone before this feature would go live?
This is already the case. In libraries that accept options via an array,
those array keys are pretty much set in stone (although you can map them
if you need to change a key).
All this does is add first-class support in the language.
Huge +1 for this feature and thank you to Nikita for working on the RFC.
--
Ryan McCue
<http://ryanmccue.info/
Matthew Leverton wrote:
This is already the case. In libraries that accept options via an array,
those array keys are pretty much set in stone (although you can map them
if you need to change a key).
The big difference here is if I accept an options array, I understand
that the keys are important and would never break backward
compatibility by changing a parameter name. This isn't a case of "if
you don't like it, then don't use it" because every function I create
now has to respect the possibility of accepting named parameters,
whether I care about it or not. And I sure hope every function I call
is created by and maintained by somebody with those same
sensibilities.
My opinion is that this really isn't as cool as it sounds, especially
since we have short array syntax. Again, I don't really care if it's
accepted into PHP, but I think it will be more of a minor nuisance for
me than anything else.
--
Matthew Leverton
Matthew Leverton wrote:
Matthew Leverton wrote:
This is already the case. In libraries that accept options via an array,
those array keys are pretty much set in stone (although you can map them
if you need to change a key).The big difference here is if I accept an options array, I understand
that the keys are important and would never break backward
compatibility by changing a parameter name. This isn't a case of "if
you don't like it, then don't use it" because every function I create
now has to respect the possibility of accepting named parameters,
whether I care about it or not. And I sure hope every function I call
is created by and maintained by somebody with those same
sensibilities.My opinion is that this really isn't as cool as it sounds, especially
since we have short array syntax. Again, I don't really care if it's
accepted into PHP, but I think it will be more of a minor nuisance for
me than anything else.
I'll second that statement. It will be more reason for me to stop following PHP
'upgrades' in the future. I'm already holding off 5.5 as it gives me nothing
that I want. This would be a reason to make that permanent.
I would add that one of the reasons I moved TO PHP was the fact that it did not
have the overhead of named parameters, amongst other things which have also been
lost over the last few years.
--
Lester Caine - G8HFL
Contact - http://lsces.co.uk/wiki/?page=contact
L.S.Caine Electronic Services - http://lsces.co.uk
EnquirySolve - http://enquirysolve.com/
Model Engineers Digital Workshop - http://medw.co.uk
Rainbow Digital Media - http://rainbowdigitalmedia.co.uk
The big difference here is if I accept an options array, I understand
that the keys are important and would never break backward
compatibility by changing a parameter name. This isn't a case of "if
you don't like it, then don't use it" because every function I create
now has to respect the possibility of accepting named parameters,
whether I care about it or not. And I sure hope every function I call
is created by and maintained by somebody with those same
sensibilities.My opinion is that this really isn't as cool as it sounds, especially
since we have short array syntax. Again, I don't really care if it's
accepted into PHP, but I think it will be more of a minor nuisance for
me than anything else.--
Matthew Leverton--
Hi, all
Would it be an option, to change the way named functions are declared?
This way you would mark a function explicitly as having named
parameters.
This increases the learning-curve for PHP, but for me, it seems a
valid approach ...
An example that comes to my mind, is to call this a "named" function
... Feel free to add a better keyword.
This would then look something like this:
named function functionHavingNamedParamsEnabled($firstParam, $secondParam) {}
function functionHavingNamedParamsDisabled($firstParam, $secondParam) {}
functionHavingNamedParamsEnabled( "secondParam" => "secondValue",
"firstParam" => "firstValue");
// Will work ...
functionHavingNamedParamsDisabled( "secondParam" => "secondValue",
"firstParam" => "firstValue");
// Will not work, because this function is not declared to support named params.
Just an idea for a compromise ..
What I don't like here would be if I'd have to add some cryptographic
char instead of a keyword to the definition of the function.
I, too, am quite neutral to this feature.
Bye,
Simon
What I don't like about named parameters is that if I build a library,
now even my parameter names are unchangeable if I don't want to break
any backward compatibility, since I never know if somebody will decide
to call my single parameter method with named parameters. Are we
prepared to go through every PHP function and make sure the names of
the parameters are set in stone before this feature would go live?
The position of parameters and the name of the function must already be
maintained... I dont see why appropriately naming variables is such a
burden.
Of course, people who use the feature are not going to assume
pre-existing code is fair-game from named parameters. As with most new
php features, it's to improve code written in the future.
Michael
On Sat, Sep 7, 2013 at 5:05 AM, Michael John Burgess
michael@mjburgess.co.uk wrote:
The position of parameters and the name of the function must already be
maintained... I dont see why appropriately naming variables is such a
burden.
I wouldn't necessarily make this objection if this were a day-1
feature. But it does bother me somewhat that all of a sudden code
retro-actively starts supporting named parameters.
The OCD in me shudders to think about now having to parse through
people's code like:
substr('length' => 1, 'string' => 'Hello World');
Now I see the function, and I have to see how they ordered their
parameters. Why was 'start' omitted... is this a warning due to using
NULL
as an int.. did the person mean 'start', etc? It's just one
example, but I know that this sort of code will start cropping up
everywhere. So that's why I call this a nuisance. It just seems like a
very marginal gain for lots of potential headaches.
But I don't mean to make a mountain out of a molehill. After giving it
some thought, I'd like some consideration to be given to providing an
explicit syntax in the RFC at least so people consider all
alternatives.
I just don't think that giving people the ability to call a function
with two well ordered parameters by using named parameters is worth
causing all future code to diverge into two drastically different
calling styles.
My strong preference would be a syntax that separates the two types of
parameters, such as the following:
function func($a, $b, ...$params, [$c = 'foo', $d = 'bar'])
{
}
func($a, $b, $extra, 'd' => 'override');
Here $a and $b are not named parameters and must be present. Extra
positional parameters are sent to $params. The parameters enclosed in
square brackets must be passed in by name as the last parameters, but
can be omitted.
I don't like the $ on the named parameter when calling because it
implies that this works:
$d = 'c';
func($a, $b, $extra, $d => 'override');
Now is 'c' overridden or 'd'?
So I'll give this issue a rest unless somebody wants to further
discuss what the concrete syntax might look like.
--
Matthew Leverton
The OCD in me shudders to think about now having to parse through
people's code like:substr('length' => 1, 'string' => 'Hello World');
Hi, Matthew
Wouldn't this just fail, because one required parameter is omitted?
You can just leave out parameters, that have a default-value.
Otherwise it's treated like calling:
substr('Hello World');
// Warning: substr()
expects at least 2 parameters, 1 given in php
shell code on line 1
I would return the same, even so the parameter-count is 2, but the 2nd
parameter is missing, but required.
Bye
Simon
hi!
Hi internals!
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
The RFC and implementation are not yet complete. I mainly want to have
feedback on the idea in general and on the Open Questions (
https://wiki.php.net/rfc/named_params#open_questions) in particular.
Love it and always wanted it! Thanks for working on that!
I quickly look at the patch and related phpt, so feel free to nicely
correct me if I ask something already covered :)
In no particular order:
. Warning: Cannot pass positional arguments after named arguments.
Aborting argument unpacking in %s on line %d
Would it make more sense to make it a fatal error? As the code will
likely not work as expected, at all. It could be a bit too harsh but
as it is a new feature, there is no BC impact and ensure good usage.
. would it make sense to have an alternative zend API to fetch one or
more argument using its name? I can see a couple of usages for such a
function
-
It would be nice to add (later once the RFC is more stable) docs
about which impacts and changes are expected for extension developers -
Do you have a fork for this RFC? Much easier to test, create snaps, etc.
Cheers,
Pierre
@pierrejoye | http://www.libgd.org
In no particular order:
. Warning: Cannot pass positional arguments after named arguments.
Aborting argument unpacking in %s on line %dWould it make more sense to make it a fatal error? As the code will
likely not work as expected, at all. It could be a bit too harsh but
as it is a new feature, there is no BC impact and ensure good usage.
I agree that continuing the function call in that case is a bad idea, but I
also really dislike throwing fatal errors when dynamic constructors are
used. An exception would be optimal here (no continued function call, but
easily recoverable), but I know I'm not allowed to introduce those...
. would it make sense to have an alternative zend API to fetch one or
more argument using its name? I can see a couple of usages for such a
function
I provide this function:
ZEND_API int zend_get_arg_num(zend_uint *arg_num_target, zend_function
*fn, char *name, int name_len, zend_ulong hash_value TSRMLS_DC);
Using it you can get the argument number from a parameter name and based on
that lookup the value of the argument as usual. Is that sufficient?
- It would be nice to add (later once the RFC is more stable) docs
about which impacts and changes are expected for extension developers
Yes, sure :)
- Do you have a fork for this RFC? Much easier to test, create snaps, etc.
Yes, it's the namedParams branch of my github fork:
https://github.com/nikic/php-src/tree/namedParams
Nikita
> Hi internals!
>
> I created an RFC and preliminary implementation for named parameters:
>
> https://wiki.php.net/rfc/named_params
>
Thanks for the feedback everyone! I will not answer every mail individually
(as many share a common topic) and will try to group things reasonably.
Dynamic named parameters syntax
-----
I'm strongly against making the parameter names in named-args calls
dynamic. If you need dynamic parameter names you can always use unpacking
notation:
foo(...[$paramName => $paramValue]);
If we allow dynamic named params virtually any syntax we choose will seem
somewhat ambiguous, e.g.:
foo(paramName => $paramValue); // is paramName a parameter name or a
constant with the parameter name?
foo($paramName => $paramValue); // is $paramName a parameter name or a
variable with the parameter name?
By clearly saying that the parameter names in the named-args syntax
(whichever we choose) are static much confusion can be avoided.
Furthermore allow non-constant parameter names will complicate the
implementation for very little practical gain.
Let only special functions accept named params
-----
There has been the suggestion that only functions that are specifically
marked (a "named" keyword) can accept named parameters and another
suggestion that only parameters that have been specifically marked can be
passed as named parameters.
In such a setting named parameters would loose all value for me.
Implementing the good old $options array isn't *that* hard after all. The
value named parameters offer to me is being able to use them everywhere I
consider them beneficial without requiring special support from the API. In
particular I think it's critical that they also work with existing internal
functions (we have quite a lot of internal functions with many independent
optional parameters) and also in cases where $options are not worth it
(just a single optional parameter).
Concerns about readability and APIs
-----
There have been some concerns regarding readability and API design relating
to named args:
By Matthew:
> I feel like this will just encourage more core PHP functions with an
> unmanageable number of parameters. Will there be any proposed
> guidelines to how future functions will make use of named parameters?
> e.g., Will we see native functions with 20 arguments
You need to shift your viewpoint. Named parameters change what "an
unmanageable number of parameters" is. Right now I would consider a
function with just two independent(!) optional parameters to already have
"an unmanageable number of parameters". Right now I would not willingly
include such a function in an API design. Named args change this. With them
there is nothing bad to a function with multiple independent optional
parameters. So: Will there be more functions that have more parameters?
Maybe. Is that a problem? No.
By Matthew:
> The OCD in me shudders to think about now having to parse through
> people's code like:
>
> substr('length' => 1, 'string' => 'Hello World');
>
> Now I see the function, and I have to see how they ordered their
> parameters. Why was 'start' omitted... is this a warning due to using
> `NULL` as an int.. did the person mean 'start', etc? It's just one
> example, but I know that this sort of code will start cropping up
> everywhere.
You will not have to parse through that code, because it's not valid. If
you fail to pass a required argument, you'll get a warning just like you
already do now. Your example is no different from the nonsensicality of
doing a substr("Foo") call.
Furthermore I think your concerns of overuse of named parameters in
contexts where they make no sense (like a substr call) are unfounded.
Looking at other languages that already support named parameters (like
Python or C#) I never noticed such patterns. Of course, every feature has a
potential for misuse, but I tend to think that most programmers *do* have
enough common sense to use features where reasonable and not at every
possible occurrence just because they can.
Renaming of parameters in signatures
-----
Until now three options were discussed:
1. Throw an `E_STRICT` (or similar) error during signature validation if a
parameter is renamed
2. Don't validate parameter renames in signature and just let people hit
the runtime error when they do the call.
3. Create an ini-setting chooses either behavior 1 or 2.
Both options 1 and 2 are not ideal, the former because it "breaks" old
code, the latter because we allow LSP violations that lead to runtime
errors. Option 3 is not really an option, we already decided a while ago
not to introduce ini-settings controlling runtime behavior.
I have another suggestion at how this could be approached: When the used
named parameter is not found we go through the inheritance hierarchy and
try to find the parameter name there. So if we have
class A {
public function foo($oldBar) { ... }
}
and
class B extends A {
public function foo($newBar) { ... }
}
and write a call
$b->foo(oldBar => $xyz);
then we'd first try the $oldBar parameter of B::foo (doesn't exist) and
then the $oldBar parameter of A::foo (exists). This could be combined with
throwing an warning/notice/whatever saying that a parameter was renamed (or
not). So the call would still work, but you'd get a notification that your
names are off (but only if you actually use named args).
Of course this does not save us in some pathological cases:
class A: public function fn($foo, $bar)
class B: public function fn($bar, $foo)
In cases where the parameter order was swapped the above approach wouldn't
work correctly.
That's it for now :)
Nikita
Nikita,
I agree with your views, although, I think your last suggestion comes
close to being close to some sort of weird method overloading (the way
I understood it).
I'd expect B::foo() to throw a warning/error and maybe stop there, and
you're considering reaching to the parent method to see if that
signature matches the function call...
While method overloading would be interesting to have (see previous
discussions on the matter ;)) this is a sort of weird and unexpected
reaching-back behaviour... I'm not sure this seems like a logical
approach, I say stick with the error and expect a consistent usage of
the (rewritten) API and prevent obscure bugs where you change an
implementation and rewrite param names when in fact you should stay
consistent with the existing code if you're extending existing
behaviour!
In fact I'm not sure if the other way around should be the norm; where
we'd force the dev to implement the same args as the parent (like it
is now: i.e. type hinting, same signature, etc); even if it's just to
do an unset($oldbar) inside something like B::foo($newBar, $oldBar =
NULL)
Was that clear?
Thanks,
Daniel Macedo
Nikita,
I agree with your views, although, I think your last suggestion comes
close to being close to some sort of weird method overloading (the way
I understood it).
Uh, I think this is a misunderstanding caused by my bad phrasing. I'll try
to clarify:
class A {
public function foo($oldBar) { ... }
}
class B extends A {
public function foo($newBar) { ... }
}
$b->foo(oldBar => $xyz);
Here $b->foo()
will call B::foo()
, not A::foo()
. The thing about
looking at the parameter names of the parent methods is just to make sure
calls are compatible with the parameter names of parent methods, even if
those names were changed during inheritance. We do not actually call the
parent method, we just borrow the parameter name from there.
In fact I'm not sure if the other way around should be the norm; where
we'd force the dev to implement the same args as the parent (like it
is now: i.e. type hinting, same signature, etc); even if it's just to
do an unset($oldbar) inside something like B::foo($newBar, $oldBar =
NULL)
Yes, throwing an error during the signature validation is the "right" thing
to do from a theoretic point of view. The issue is just that it breaks old
code which didn't make sure that parameter names between parent and child
lined up. "Break" is a bit too much here as it would still run, just
throwing an E_STRICT. This is what I'd like to go for, but others disagree
so I tried to offer an alternative solution.
Nikita
What about:
class Giant {
public function foo( $height, $width ) { ... }
}
class FallenOverGiant extends Giant {
public function foo( $width, $height ) { ... }
}
There's nothing to stop you doing that; I think it's actually done in some
of the codebases I work on. Or:
class Rectangle {
public function paint( $height, $width ) { ... }
}
class Square extends Rectangle {
public function paint( $width, $unused = null ) { return
parent::paint( $width, $width }
}
Here I don't want someone to be able to use the second parameter (you can
argue over whether the inheritance should be that way round, but that's the
way code is currently written).
I don't think there's a clever way of pleasing everyone here. In which
case, the principle of least surprise definitely applies. Crawling the
inherited signatures definitely feels like a shim rather than clever design.
--G
Nikita,
I agree with your views, although, I think your last suggestion comes
close to being close to some sort of weird method overloading (the way
I understood it).Uh, I think this is a misunderstanding caused by my bad phrasing. I'll try
to clarify:class A { public function foo($oldBar) { ... } } class B extends A { public function foo($newBar) { ... } } $b->foo(oldBar => $xyz);
Here
$b->foo()
will callB::foo()
, notA::foo()
. The thing about
looking at the parameter names of the parent methods is just to make sure
calls are compatible with the parameter names of parent methods, even if
those names were changed during inheritance. We do not actually call the
parent method, we just borrow the parameter name from there.In fact I'm not sure if the other way around should be the norm; where
we'd force the dev to implement the same args as the parent (like it
is now: i.e. type hinting, same signature, etc); even if it's just to
do an unset($oldbar) inside something like B::foo($newBar, $oldBar =
NULL)Yes, throwing an error during the signature validation is the "right" thing
to do from a theoretic point of view. The issue is just that it breaks old
code which didn't make sure that parameter names between parent and child
lined up. "Break" is a bit too much here as it would still run, just
throwing an E_STRICT. This is what I'd like to go for, but others disagree
so I tried to offer an alternative solution.Nikita
Yes, throwing an error during the signature validation is the "right" thing
to do from a theoretic point of view. The issue is just that it breaks old
code which didn't make sure that parameter names between parent and child
lined up. "Break" is a bit too much here as it would still run, just
throwing an E_STRICT. This is what I'd like to go for, but others disagree
so I tried to offer an alternative solution.
It isn't feasible to suddenly start spewing E_STRICT
errors on inherited
methods that change the name of the parent's arguments. The name of the
arguments has never mattered before and tons of code will no longer be
E_STRICT
clean even if they don't use named parameters.
I think you are over-thinking this case actually. I would prefer to just
keep it simple. If someone does a named parameter call to a method that
doesn't have a parameter with a specified parameter it is an error,
regardless of how that came to be. If there is a parent method with the
parameter name, it doesn't matter since that is not the method they are
calling. Just keep it simple and generate an error just on that call.
The fix for the user in this case may very well be to go and make the
parameter names match the parent method, but let them worry about that.
-Rasmus
I think you are over-thinking this case actually. I would prefer to just
keep it simple. If someone does a named parameter call to a method that
doesn't have a parameter with a specified parameter it is an error,
regardless of how that came to be. If there is a parent method with the
parameter name, it doesn't matter since that is not the method they are
calling. Just keep it simple and generate an error just on that call.
The fix for the user in this case may very well be to go and make the
parameter names match the parent method, but let them worry about that.-Rasmus
Thanks, this makes more sense to me, and is surely a less complicated
implementation.
> > I created an RFC and preliminary implementation for named parameters:
> >
> > https://wiki.php.net/rfc/named_params
> >
>
Awesome work!
>
> Let only special functions accept named params
> -----
>
Proposal makes sense though there's still the challenge how to deal with the 'api mismatch' problem.
I'm still undecided about 'mixing' positional & named arguments:
An example use case for **kwargs here:
http://www.python-requests.org/en/latest/api/
If you declare:
request($method, $url, ...$args)
Would $args collect 'method' and 'url' ?
request(method => 'post', url => 'foo/');
> Renaming of parameters in signatures
> -----
>
> Until now three options were discussed:
> 1. Throw an `E_STRICT` (or similar) error during signature validation if a parameter
> is renamed 2. Don't validate parameter renames in signature and just let people
> hit the runtime error when they do the call.
> 3. Create an ini-setting chooses either behavior 1 or 2.
>
> class A {
> public function foo($oldBar) { ... }
> }
> and
> class B extends A {
> public function foo($newBar) { ... }
> }
My preference would be to only support named parameters based on the initial declaration $oldBar (much simpler expectations).
$c = new B;
$c->foo(oldBar => 'hello');
$c->foo(newBar => 'hello'); // Warning, no named parameter 'newBar' found, Warning first argument missing ...
Lastly, using the same syntax "..." for declaring variadics and "unpacking" seems odd to me.
Some ideas for a different syntax:
$params = ['oldBar' => 'hello'];
$c->foo($params...);
$c->foo((var)$params);
$c->foo((...)$params);
My preference is the third since it looks like we're casting an array to named parameters.
I created an RFC and preliminary implementation for named parameters:
https://wiki.php.net/rfc/named_params
I really like the idea!
My preference would be to only support named parameters based on the initial declaration $oldBar (much simpler expectations).
I bet that there is already many code "renaming" the parameters so I
agree with Nikita to match it against the called instance (and not the
initial declaration).
As for the open questions I would prefer something from the "can use
keywords" section.
I think one with the dollar sign would be best since thats how the
declaration looks like, e.g. "$foo => xxx" or "$foo: ...".
I'm still undecided about 'mixing' positional & named arguments: An
example use case for **kwargs here:
http://www.python-requests.org/en/latest/api/ If you declare:
request($method, $url, ...$args) Would $args collect 'method' and
'url' ? request(method => 'post', url => 'foo/');
No. With positional arguments:
function foo($bar, $foobar, ...$x) {}
foo(1, 2);
Then $x will be empty, since it only collects "left-over" arguments, I
suppose. The same applies for named arguments. In the case you used,
$args would be empty, as $method and $url pick up those named arguments.
Andrea Faulds
http://ajf.me/