> On Feb 23, 2020, at 2:00 AM, Mike Schinkel <mike@newclarity.net> wrote:
> On Feb 22, 2020, at 5:56 AM, Rowan Tommins <rowan.collins@gmail.com> wrote:
>> One of the reasons it is confusing is because developers are currently
>> required to use the ampersand in one place and not the other. Making
>> it always used removes said confusion as they would no longer be a
>> reason to have to remember when and when not to use the ampersand
>> anymore.
>
> Maybe. I think a larger part of it is that references themselves are a slightly confusing concept, and the fact that & looks like an operator of its own (and is often documented that way) but is really an annotation on other operators/commands. That is, the & in $foo = &$bar and return &$bar doesn't modify $bar, it modifies = and return, respectively.
>
> Making the rules more logical and symmetrical would perhaps be more helpful to new users than it is to established users, particularly those who've known multiple versions of the language already.
You call out the use of the ampersand being viewed as an operator acting on a variable as problematic, but that is already baked into current PHP, not going to change any time soon if ever, and is orthogonal to this RFC.
So whether or not people find the ampersand operator to be confusing that is irrelevant to the debate posed by Nikita's RFC over whether we should make the use of ampersand related to passing-by-reference be more consistent.
>> There is a potential "PR" cost of this change that should be weighed
>> against the advantages.
>>
>> To say "We fixed something that in hindsight we've since determined was
>> a problem." How is this a concern?
>
> The concern is that the costs will be much more visible to users than the benefits, and they will resent the core developers pushing that requirement onto them, rather than thanking then for their hard work.
>
> As I said, that's not an absolute reason not to do it, it's a cost to be weighed.
Nikita's RFC proposes that the ampersand would be optional at the calling site, so is it really a concern that developers will resent something that is optional?
Yes Nikita mentioned that a future "edition" might make is a requirement, but even then it will still be optional — developers can choose not to use the new edition — and I think the resentment will come more from the concept of forcing an "edition" on developers than any specific feature. Note that I plan to post soon about how I think we can alleviate that.
So we can debate the PR "cost" of requiring ampersands at the call site when the requiring RFC is on the table.
As a side note, I remember thinking "WTF?!?" when the requirement to use an ampersand at the calling site was removed. It is possible your analysis of PR cost is discounting the potential large number of people who will think adding it back is a good think.
>>> I'm also not very keen on internal functions being able to do things
>> that can't be replicated on userland, and this RFC adds two: additional
>> behaviour for existing "prefer-ref" arguments, and new "prefer-value"
>> arguments
>>
>> So what specific problems would having these enhancement cause for the
>> language?
>
> There are two problems I have with internal-only features in general: the inability to polyfill and extend, and the requirement for a separate mental model.
>
> As an example of the first, the RFC mentions using call_user_func with a call-site annotation to forward the parameter by reference. The reason for allowing that also applies to a user-defined wrapper like call_with_current_user or call_with_swapped_parameters, but there's no syntax for those to be marked "prefer-val".
Let's analyze.
In this case there does not appear to be a need for "prefer-val." And Nikita's RFC adds functionality we currently do not have — ability to pass by reference to call_user_func() so that is a win over status quo as it gains a feature that we previously internal-only:
<?php
function current_user():int {
return 1;
}
function foobar( int $current_user, int &$foo, int $bar ) {
$foo++;
$bar++;
}
function call_with_current_user(Callable $callable, int &$foo, int $bar ) {
return call_user_func( $callable, current_user(), &$foo, $bar );
}
$foo = 0;
$bar = 0;
call_with_current_user( 'foobar', &$foo, $bar );
echo $foo; // prints 1
echo $bar; // prints 0
Now if you want to use call_user_func_array() then I agree we are missing functionality. Consider this example which envisions a new function called `func_is_byref_arg()`. Yes the function name is a horrible name but consistent with existing functions for related purposes:
<?php
function current_user():int {
return 1;
}
function foobar( int $current_user, int ...&$args ) {
foreach( $args as $i => $f ) {
$args[$i]++;
}
}
function call_with_current_user(Callable $callable, int ...&$args ) {
array_unshift(&$args,current_user());
$temp_args = $args;
$result = call_user_func_array( $callable, &$temp_args );
foreach( $temp_args as $i => $t ) {
if ( func_is_byref_arg( $i, $args ) ) {
$args = $temp_args[$i];
}
}
return $result;
}
$foo = 0;
$bar = 0;
$baz = 0;
call_with_current_user( 'foobar', &$foo, $bar, $baz );
echo $foo; // prints 1
echo $bar; // prints 0
echo $baz; // prints 0
In my example func_is_byref_arg($pos[,$variadic_arg]):bool accepts one parameter if you are checking for by-ref positionally, and two if you are introspecting a variadic parameter.
So I argue we should fill in the holes of the RFC that introduces a feature that to help developers write more robust code instead of decline an RFC for imperfections in its first draft.
> As an example of the second, even under strict settings, calls to certain internal functions will have an optional & at the call site, which changes their behaviour.
>
> To those without knowledge of the core, those functions simply have to be remembered as "magic", because their behaviour can't be modelled as part of the normal language.
I am unclear how the optional ampersand at the call site will change the behavior.
As I understand the RFC the behavior will still be driven by the ampersand at the declaration site. The presence or absence of ampersand at a call still will merely be decoration that allows developers to better convey their intent.
Can you please give an example of how this RFC would change behavior at call site compared to a call site where the ampersand did not exist, given the behavior of this RFC?
>>> My current opinion is that I'd rather wait for the details of out and
>> inout parameters to be worked out, and reap higher gains for the same
>> cost. For instance, if preg_match could mark $matches as "out", I'd be
>> more happy to run in a mode where I needed to add a call-site keyword.
>>
>> This sounds like preferring perfect in the (potentially distant) future
>> vs. much better today.
>
>
> No, it's preferring to hold out for a little bit more value to weigh against my evaluation of the cost.
>
> This is, when followed through to its conclusion of mandatory marking, a disruptive change to every piece of code, so we need to decide if the disruption is worth it.
That is disingenuous. The RFC does not require mandatory use, period.
The "cost" you worry about will not exist unless and until a future RFC proposes to make it mandatory and that RFC is accepted.
Further, your cost analysis does not appear to consider the cost of status quo and this RFC's ability to reduce that cost.
Using Nikita's RFC example there is a potential real-world cost to getting the following wrong in a userland project:
$ret = array_slice($array, 0, 3);
$ret = array_splice($array, 0, 3);
With Nikita's RFC developers could chose to start using ampersand at the calling site for these type of methods. Let's consider that I write the following:
array_slice(&$array, 0, 3);
array_splice(&$array, 0, 3);
With this RFC (I assume) an error could be generated on array_splice(&$array, 0, 3)saying that I cannot pass the array by reference. Today we don't get that. This alone could reduce errors that I have seen in source code and I admittedly have committed myself.
Said succinctly, there is a (IMO significant) cost to doing nothing that your analysis appears to ignore.
> It's also the second change in the same place, and we should be sure that we've got it right this time, and won't require a third change in the near future.
I don't particularly see a problem with requiring a third change in the future. Hindsight is a wonderful clarifier. And I believe elsewhere you have been debating me over the need for incremental change. Caveat emptor.
> For instance, if out parameters were added, would the same line of code end up going from optional &, to forbidden &, to mandatory &, to mandatory "out"?
My view is that we should actually hash those concerns out and move forward rather than state them in the abstract and let the fact that legitimate concerns *might* exist derail an improvement to the language.
Since there are not infinite potentials, let's just address your specific concerns here. My straw man proposal is that if we add an `out` keyword exists then a developer could use either `out` or `&` but not both. Then in a future "edition" of pHP it would be possible that we disallow `&` if enough people agree that that is better. Or we could leave as either/or. Allowing ampersand at a call site today does not block potential future `out` keywords AFAICT.
For me I don't care which it is as long as there is a calling site notation that allows a developer to write code indicating intent and for other developers to read code and see that intent.
Status quo waiting for some future potential that may not arrive for years does not get us there in the near term, but Nikita's RFC would.
> I'm not strongly against the idea, but the advantages just don't feel quite strong enough, so if I had a vote, I'd currently be inclined to vote no.
Heh. My vote would yes. And since neither of us have a vote I guess it would be applicable to say they cancel each other's vote out. Or not. :-D
-Mike