On 07/04/2020 13:44, Nikita Popov wrote:
Make named-parameter opt-in in some fashion, so that parameter names
only need to be preserved for methods that have the opt-in marker. I'm not
a fan of this, as it greatly diminishes the practical usefulness of named
parameters.
I generally prefer the idea of named parameters requiring some sort of
opt-in at the definition site.
I feel like this would solve a whole bunch of problems:
- LSP violations could be stricter errors, because they would show up
once the parent class opted in, not as soon as you upgraded your PHP
version.
- Similarly, library authors would have a chance to tidy up their
parameter naming, knowing that it was going to be a part of the
compatibility contract for future versions. Without an opt-in, they
might find themselves unable to fix poor or inconsistent names without
declaring a BC break.
- Internal functions could also be "opted in" gradually, giving core
devs and extension authors time to sort out any that do odd things with
ZPP or ZEND_NUM_ARGS.
- Variadic functions could be automatically "opted out" without needing
a particular special case (they could just give a generic "function
doesn't support named params" error).
The biggest downside I can see is that there's no obvious way of library
code opting in to named parameters when run under PHP 8 (or whenever we
add them) but also compiling successfully under earlier versions. That
would certainly slow the spread of the feature rather drastically, which
would be a shame. I wonder if there's a clever syntax we could adopt
that would avoid this.
In some ways, it would be nice to go one step further, and separate the
names presented to callers from the names used inside the function body.
Since parameters become ordinary mutable variables for the rest of the
function, it can be tempting to think of them as part of the
implementation, not part of the signature. This can lead to them
naturally changing both over time, and in inheritance hierarchies.
For instance, an interface might define a parameter as "$id", but a
concrete class want to label it as "$requestedFoobarId" to make the
implementation clearer. It would be nice to be able to (optionally)
define both. Straw man example syntax, using ":$foo" as opt-in, and
"foo: $bar" as aliasing:
function get( int id: $requestedFoobarId, boolean :$deep )
That would essentially be sugar for:
<<AllowCallingWithNamedParams>>
function get( int $id, boolean $deep ) {
$requestedFoobarId = $id;
unset($id);
// ...
}
In the same way, normal positional parameters could be (and in some
languages are) seen as sugar for this:
function get( int $1, boolean $2 ) {
$requestedFoobarId = $1;
$deep = $2;
// ...
}
It would also give another option for the LSP problem - if the parent
class or interface opts into named parameters, the child class gets
implicit aliases if it doesn't specify any:
interface Foo { function thing( :$id ); } // named parameter "id"
class Bar implements Foo { function thing( id: $barId ) {} } // explicit
alias matches interface, $bar->thing(id: 42) will set $barId=42
class Baz implements Foo { function thing( $bazId ) {} } // implicitly
aliased, $baz->thing(id: 42) will set $bazId=42 based on the name in the
interface
class Wrong implements Foo { function thing( :$wrongName ) {} } //
Error: tries to accept named parameter "wrongName", but interface
requires it to accept named parameter "id" instead
Regards,
--
Rowan Tommins (né Collins)
[IMSoP]
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php