RE: [PHP-DEV] [RFC] Named parameters
| From: | Robert Stoll | Date: | Sat, 07 Sep 2013 21:13:24 +0000 |
| Subject: | RE: [PHP-DEV] [RFC] Named parameters | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-68956@lists.php.net to get a copy of this message | ||
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 parameters
>
> 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
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