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

Reply via email to