Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Larry Garfield
On Mon, Jan 23, 2023, at 3:52 PM, Dan Ackroyd wrote:
> On Mon, 23 Jan 2023 at 20:51, Larry Garfield  wrote:
>>
>> On Mon, Jan 23, 2023, at 12:32 PM, Dan Ackroyd wrote:
>>
>> >
>> > $fnConstructor = Closure::fromClassConstructor(Zoq::class);
>> > // signature of $fnConstructor is the same as `function(Fot $fot): Zoq`
>> >
>> > Or for individual methods:
>> >
>> > $fnMethod = Closure::fromClassMethod(Zoq::class, 'Pik');
>> > // signature of $fnMethod is the same as `function(Zoq $zoq, string
>> > $zebranky): Frungy`
>>
>> I don't think that actually helps.  If you have the object already,
>
> Neither of new functions I was suggesting have the object already.
> Only the type.
>
>> If you do not have the object already, then we run back into the issue
>> I pointed out before where we need to differentiate a bindable from
>> needs-binding callable,
>
> That's not what I suggesting.
>
> Danack wrote:
>>
>> $fnConstructor = Closure::fromClassConstructor(Zoq::class);
>> signature of $fnConstructor is the same as `function(Fot $fot): Zoq`
>
> That doesn't need a binding at all.
>
> Danack wrote:
>>
>> $fnMethod = Closure::fromClassMethod(Zoq::class, 'Pik');
>> signature of $fnMethod is the same as `function(Zoq $zoq, string
>> $zebranky): Frungy`
>
> First parameter is the object to be operated on. You wouldn't need to
> do any binding. *magic* would happen inside the function to take care
> of that.

Oh, I see what you're getting at.  I missed the signature on first read.  So 
you're saying that would generate a callable equivalent to:

$fnMethod = fn (Zok $zok, string $zebranky): Frungy => $zok->Pik($zebranky);

That's an interesting idea, though probably not self-evident to many people.  
If we wanted to do that, I'd probably push for something more compact as a 
syntax, and a bit more auto-refactorable.  I think the Ara language had syntax 
for something like this, $$->Pik(...) ?  If I'm remembering correctly, which I 
may or may not be?

(We're also now rather far afield from the OP's request, I think.)

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callablesyntax on non-static methods, statically

2023-01-23 Thread Christoph M. Becker
On 23.01.2023 at 19:22, Robert Landers wrote:

> Speaking of partial application, it'd be amazing if it were available
> with the current closure syntax:
>
> $func = fn($x, $y, $z) => echo $x + $y + $z;
> $plus1 = $func(..., 1);
> $plus2n1 = $func(2, 1, ...);
>
> $a = $plus1(1, 2);
> $b = $plus2n1(5);
>
> I spent a few days last summer trying this out, but couldn't get the
> grammar parser to accept it. I think I have a local branch if someone
> would be willing to work on it with me. At least point me in the right
> direction. I don't have much free time these days, but it is certainly
> doable.

There has been an RFC for this[1] (including an implementation), which
had been declined.

[1] 

--
Christoph M. Becker

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Dan Ackroyd
On Mon, 23 Jan 2023 at 20:51, Larry Garfield  wrote:
>
> On Mon, Jan 23, 2023, at 12:32 PM, Dan Ackroyd wrote:
>
> >
> > $fnConstructor = Closure::fromClassConstructor(Zoq::class);
> > // signature of $fnConstructor is the same as `function(Fot $fot): Zoq`
> >
> > Or for individual methods:
> >
> > $fnMethod = Closure::fromClassMethod(Zoq::class, 'Pik');
> > // signature of $fnMethod is the same as `function(Zoq $zoq, string
> > $zebranky): Frungy`
>
> I don't think that actually helps.  If you have the object already,

Neither of new functions I was suggesting have the object already.
Only the type.

> If you do not have the object already, then we run back into the issue
> I pointed out before where we need to differentiate a bindable from
> needs-binding callable,

That's not what I suggesting.

Danack wrote:
>
> $fnConstructor = Closure::fromClassConstructor(Zoq::class);
> signature of $fnConstructor is the same as `function(Fot $fot): Zoq`

That doesn't need a binding at all.

Danack wrote:
>
> $fnMethod = Closure::fromClassMethod(Zoq::class, 'Pik');
> signature of $fnMethod is the same as `function(Zoq $zoq, string
> $zebranky): Frungy`

First parameter is the object to be operated on. You wouldn't need to
do any binding. *magic* would happen inside the function to take care
of that.

> I think that's a prerequisite for adding any dedicated syntax
> for "make a closure that doesn't work until it gets bound".

To be clear, I don't support anything like that. As I wrote:

Danack wrote:
>
> That sounds like a complete non-starter. Adding something to the
> language that produces a closure that can't be called would be an
> instant new entry for PHPSadness.

cheers
Dan
Ack

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Larry Garfield
On Mon, Jan 23, 2023, at 12:32 PM, Dan Ackroyd wrote:
> On Sun, 22 Jan 2023 at 17:45, Ollie Read  wrote:
>>
>> Hello all,
>
> Hi Ollie,
>
>> I've created a feature request issue on GitHub (here: 
>> https://github.com/php/php-src/issues/10414), but I have been advised that 
>> it's best to post here.
>> ...
>> I think we could delay the error until the closure was called.
>
> That sounds like a complete non-starter. Adding something to the
> language that produces a closure that can't be called would be an
> instant new entry for PHPSadness.
>
>> Whereas it would be much nicer to have the following:
>>
>> ```
>> $collection->filter(Str::empty(...));
>> ```
>>
>> In this situation, the collection library would be responsible for binding 
>> the
>> closure to the value it is iterating.
>
> How would the collection library know it was safe to bind the closure
> to each value it was iterating over? It sounds really type unsafe.
>
>
>> What I would like to introduce/suggest, is the ability to create a closure
>> from a method using the first-class-callable syntax...
>>
>> The more I think about it, the more I think this may require a new ...
>
> I think people should say clearly what the problem they are trying to
> solve first, before suggesting solutions.
>
> I think there's at least a couple of problems that can be thought about:
>
> i. Although the first-class-callable syntax allowed avoiding string
> based programming for most callables, it doesn't support referring to
> some things that you would want to call, including both instance
> methods, and constructors*.
>
> ii. Representing an instance method requires at least two pieces of
> info; which class it belongs to (which can be used to find the
> constructor) and the parameters of the method itself. That doesn't
> naturally fit into a closure.
>
> iii. The appropriate syntax for referencing a class instance method
> without it being string based isn't obvious. Or at least it isn't
> obvious to me.
>
> iv. Writing code that for callback methods is longer than it could be,
> e.g. as Larry Garfield wrote:
>
>> So what you're really looking for is a shorter way to write this:
>>
>> foo(fn(Str $s) => $s->beep());
>
>
> At the risk of suggesting an abomination, given a class of:
>
> class Zoq
> {
> public function __construct(private Fot $fot) {}
>
> public function Pik(string $zebranky): Frungy {...}
> }
>
> If it was possible to generate callable for the constructor with:
>
> $fnConstructor = Closure::fromClassConstructor(Zoq::class);
> // signature of $fnConstructor is the same as `function(Fot $fot): Zoq`
>
> Or for individual methods:
>
> $fnMethod = Closure::fromClassMethod(Zoq::class, 'Pik');
> // signature of $fnMethod is the same as `function(Zoq $zoq, string
> $zebranky): Frungy`
>
> That sort of looks like a solution to most of the problems I think exist.
>
> For your particular problem, I believe that would allow:
>
> $fnMethod = Closure::fromClassMethod(Str::class, 'empty');
> $collection->filter($fnMethod);
>
> Which isn't shorter, but at least allows passing the callables around
> with the type inspectable. Though it might be nicer if PHP had the
> ability to definte function signatures types.
>
> That sort of solution obviously doesn't address the problem of having
> to refer to the class method as a string, but as I said, I don't have
> a suggestion for that. Well, other than to use a different syntax.**

I don't think that actually helps.  If you have the object already, then making 
an FCC from it already works:

https://3v4l.org/GTAGR

If you do not have the object already, then we run back into the issue I 
pointed out before where we need to differentiate a bindable from needs-binding 
callable, which is already an issue (though one I've not run into).  I think 
that's a prerequisite for adding any dedicated syntax for "make a closure that 
doesn't work until it gets bound".

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Dan Ackroyd
On Sun, 22 Jan 2023 at 17:45, Ollie Read  wrote:
>
> Hello all,

Hi Ollie,

> I've created a feature request issue on GitHub (here: 
> https://github.com/php/php-src/issues/10414), but I have been advised that 
> it's best to post here.
> ...
> I think we could delay the error until the closure was called.

That sounds like a complete non-starter. Adding something to the
language that produces a closure that can't be called would be an
instant new entry for PHPSadness.

> Whereas it would be much nicer to have the following:
>
> ```
> $collection->filter(Str::empty(...));
> ```
>
> In this situation, the collection library would be responsible for binding the
> closure to the value it is iterating.

How would the collection library know it was safe to bind the closure
to each value it was iterating over? It sounds really type unsafe.


> What I would like to introduce/suggest, is the ability to create a closure
> from a method using the first-class-callable syntax...
>
> The more I think about it, the more I think this may require a new ...

I think people should say clearly what the problem they are trying to
solve first, before suggesting solutions.

I think there's at least a couple of problems that can be thought about:

i. Although the first-class-callable syntax allowed avoiding string
based programming for most callables, it doesn't support referring to
some things that you would want to call, including both instance
methods, and constructors*.

ii. Representing an instance method requires at least two pieces of
info; which class it belongs to (which can be used to find the
constructor) and the parameters of the method itself. That doesn't
naturally fit into a closure.

iii. The appropriate syntax for referencing a class instance method
without it being string based isn't obvious. Or at least it isn't
obvious to me.

iv. Writing code that for callback methods is longer than it could be,
e.g. as Larry Garfield wrote:

> So what you're really looking for is a shorter way to write this:
>
> foo(fn(Str $s) => $s->beep());


At the risk of suggesting an abomination, given a class of:

class Zoq
{
public function __construct(private Fot $fot) {}

public function Pik(string $zebranky): Frungy {...}
}

If it was possible to generate callable for the constructor with:

$fnConstructor = Closure::fromClassConstructor(Zoq::class);
// signature of $fnConstructor is the same as `function(Fot $fot): Zoq`

Or for individual methods:

$fnMethod = Closure::fromClassMethod(Zoq::class, 'Pik');
// signature of $fnMethod is the same as `function(Zoq $zoq, string
$zebranky): Frungy`

That sort of looks like a solution to most of the problems I think exist.

For your particular problem, I believe that would allow:

$fnMethod = Closure::fromClassMethod(Str::class, 'empty');
$collection->filter($fnMethod);

Which isn't shorter, but at least allows passing the callables around
with the type inspectable. Though it might be nicer if PHP had the
ability to definte function signatures types.

That sort of solution obviously doesn't address the problem of having
to refer to the class method as a string, but as I said, I don't have
a suggestion for that. Well, other than to use a different syntax.**

cheers
Dan
Ack

* constructors having their own terrible history.

** https://news-web.php.net/php.internals/114542

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Robert Landers
On Mon, Jan 23, 2023 at 6:31 PM Larry Garfield  wrote:
>
> On Mon, Jan 23, 2023, at 10:53 AM, Ollie Read wrote:
> > There's definitely similarity, but I would say it sits somewhere
> > between the two. Rather than reference a partial method call, or create
> > a closure for a method, you're delaying a method call. Or rather,
> > referencing a method. We have the ::class pseudo property, so I see
> > this like an equivalent, but for methods.
>
> So what you're really looking for is a shorter way to write this:
>
> foo(fn(Str $s) => $s->beep());
>
> Now you're definitely in the realm of PFA, pipes, and that kind of 
> functionality.  And, sadly, Internals has shown a great deal of resistance to 
> that kind of functionality.  I have a user-space implementation of pipes that 
> includes utilities to do something similar[1], but most functional languages 
> I know also don't have a really strong native way to "turn around" a call 
> like that.
>
> I'd love a solution for that, but so far it has proven both elusive and 
> controversial.
>
> --Larry Garfield
>
> [1] https://github.com/Crell/fp/blob/master/src/object.php#L28
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

Speaking of partial application, it'd be amazing if it were available
with the current closure syntax:

$func = fn($x, $y, $z) => echo $x + $y + $z;
$plus1 = $func(..., 1);
$plus2n1 = $func(2, 1, ...);

$a = $plus1(1, 2);
$b = $plus2n1(5);

I spent a few days last summer trying this out, but couldn't get the
grammar parser to accept it. I think I have a local branch if someone
would be willing to work on it with me. At least point me in the right
direction. I don't have much free time these days, but it is certainly
doable.

Robert Landers
Software Engineer
Utrecht NL

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Larry Garfield
On Mon, Jan 23, 2023, at 10:53 AM, Ollie Read wrote:
> There's definitely similarity, but I would say it sits somewhere 
> between the two. Rather than reference a partial method call, or create 
> a closure for a method, you're delaying a method call. Or rather, 
> referencing a method. We have the ::class pseudo property, so I see 
> this like an equivalent, but for methods.

So what you're really looking for is a shorter way to write this:

foo(fn(Str $s) => $s->beep());

Now you're definitely in the realm of PFA, pipes, and that kind of 
functionality.  And, sadly, Internals has shown a great deal of resistance to 
that kind of functionality.  I have a user-space implementation of pipes that 
includes utilities to do something similar[1], but most functional languages I 
know also don't have a really strong native way to "turn around" a call like 
that.

I'd love a solution for that, but so far it has proven both elusive and 
controversial.

--Larry Garfield

[1] https://github.com/Crell/fp/blob/master/src/object.php#L28

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Larry Garfield
On Mon, Jan 23, 2023, at 10:08 AM, Robert Landers wrote:

> In my mind, Test::Func(...) should be treated the same as ['Test',
> 'Func'] or 'Test::Func' until it is called and if some fancy framework
> wants to do something special with the closure, it can do so. FWIW, I
> didn't even know this syntax checked anything until today. I can think
> of a number of cases where delaying the error to actual execution is
> beneficial.
>
> 1. Just because the method/object doesn't exist, doesn't mean it won't
> exist by the time it is called -- this is PHP after all.
> 2. I can have a file with 100 million of these things without
> triggering any autoloading.
> 3. PHPStorm currently doesn't trigger this syntax as an error.

This ship has long since sailed.  Test::func(...) produces a \Callable object, 
using the Closure::fromCallable() mechanism internally.  One important 
advantage (and why Nikita favored it over most other callable syntaxes) is that 
it respects scope visibility better than passing around a buncha strings.

Changing that at this point is a major API break that is not going to happen.

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Larry Garfield
On Mon, Jan 23, 2023, at 9:39 AM, Ollie Read wrote:
> You are absolutely correct. I guess the solution would be to handle it 
> differently in this case.
>
> Creating a closure from a static method would be fine, as it creates a 
> static closure, but when attempting to create a static closure from a 
> non-static method, it would instead return a closure that errors if it 
> isn't bound to an appropriate object. You'd most likely want to 
> restrict this to public methods only, which would help with the 
> security issues.

Then don't make it a non-static method?  Using an object method as a static 
method has been bad practice for as long as I can remember and an error since 
sometime recently, I think, so let's not do that.


> There's already a check there that throws an error, so we can already 
> tell the difference there, but the tricky part will be in the returned 
> closure. Perhaps something like "BindingClosure" that throws the static 
> error when attempting to call it unbound, or better yet, a more 
> descriptive error about it requiring binding.
>
> Would that be feasible?

By the time the error is thrown is too late.  It's a distinction that needs to 
be made before the bind.  So you could do like:

if ($fn->needsBinding()) {
  $fn = $fn->bindTo($o);
}

(Or something.)

That said, it sounds like you're talking about something different anyway that 
is probably unfeasible.

Also, please do not top post.

--Larry Garfield

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Ollie Read
There's definitely similarity, but I would say it sits somewhere between the 
two. Rather than reference a partial method call, or create a closure for a 
method, you're delaying a method call. Or rather, referencing a method. We have 
the ::class pseudo property, so I see this like an equivalent, but for methods.

On Mon, Jan 23, 2023, at 4:50 PM, Deleu wrote:
> 
> 
> On Mon, Jan 23, 2023, 1:16 PM Ollie Read  wrote:
>> Oh, I didn't mean to suggest that it automatically binds.
>> 
>> My second suggestion for how to achieve this does require some sort of 
>> automation. If you create a closure from Str::someMethod($arg1, $arg2) where 
>> someMethod isn't static, it should create a closure with the signature 
>> fn(Str $object, $arg1, $arg2), which would wrap a call to [$object, 
>> 'someMethod]($arg1, $arg2).
> 
> I think this starts to wonders in the realm of Partial Function Application 
> https://wiki.php.net/rfc/partial_function_application
> 

---
Best Regards,
*Ollie Read*


Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Deleu
On Mon, Jan 23, 2023, 1:16 PM Ollie Read  wrote:

> Oh, I didn't mean to suggest that it automatically binds.
>
> My second suggestion for how to achieve this does require some sort of
> automation. If you create a closure from Str::someMethod($arg1, $arg2)
> where someMethod isn't static, it should create a closure with the
> signature fn(Str $object, $arg1, $arg2), which would wrap a call to
> [$object, 'someMethod]($arg1, $arg2).


I think this starts to wonders in the realm of Partial Function Application
https://wiki.php.net/rfc/partial_function_application


Re: [PHP-DEV] [RFC] Pass Scope to Magic Accessors

2023-01-23 Thread Nicolas Grekas
> On 1/19/23 18:43, Ilija Tovilo wrote:
> > You're right, we'll try to improve the wording and provide a handful of
> > examples. Essentially, $callingScope should contain the class name of
> > the calling scope, so the place where the magic method was called. When
> > the calling scope is not a class (global scope, function, static
> > closure, etc.) null is passed instead.
>
> Thank you, this is more clear now.
>
> > given property. This is not a problem when the property is supposed to
> > be public but becomes difficult when trying to restrict access to it. It
>
> If I understand the proposal correctly, then any access restriction
> would effectively be a Gentleman's agreement only, because nothing is
> preventing me from calling '$someObj->__get('someProp',
> $someObj::class);', no?
>

Yep. That's already the case: using a rebound close, we can fake any scope
already so this is not new capability.



> Honestly so far I fail to see the cost/benefit ratio to be acceptable
> for the added complexity here. Not just the implementation complexity
> within the language itself, but also because this will need to be
> documented within the PHP manual and integrated within tooling, such as
> static analyzers.
>
> Is there some real-world example where I would employ this type of
> access control within the magic methods and where "not documenting the
> property to not expose it to the IDE autocompletion" would not be
> sufficient, but this easily circumventable check would be?
>
> My only use case of __get() so far was making properties visible to the
> public, while restricting write access, so this is not a problem I
> needed to solve before.
>

Legit concerns. I'm going to prepare a more extensive use case so the
motivations of RFC become more obvious.

I'll get back on this thread when ready. Stay tuned :)

Nicolas


Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Ollie Read
Oh, I didn't mean to suggest that it automatically binds.

My second suggestion for how to achieve this does require some sort of 
automation. If you create a closure from Str::someMethod($arg1, $arg2) where 
someMethod isn't static, it should create a closure with the signature fn(Str 
$object, $arg1, $arg2), which would wrap a call to [$object, 
'someMethod]($arg1, $arg2).

However, perhaps the simplest solution, and one that could be done realtively 
easily and quickly, would be to delay the error, and allow static closures to 
bound with Closure::bind() if they represent a non-static method.

---
Best Regards,
*Ollie Read*


Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Robert Landers
On Mon, Jan 23, 2023 at 4:39 PM Ollie Read  wrote:
>
> You are absolutely correct. I guess the solution would be to handle it 
> differently in this case.
>
> Creating a closure from a static method would be fine, as it creates a static 
> closure, but when attempting to create a static closure from a non-static 
> method, it would instead return a closure that errors if it isn't bound to an 
> appropriate object. You'd most likely want to restrict this to public methods 
> only, which would help with the security issues.
>
> There's already a check there that throws an error, so we can already tell 
> the difference there, but the tricky part will be in the returned closure. 
> Perhaps something like "BindingClosure" that throws the static error when 
> attempting to call it unbound, or better yet, a more descriptive error about 
> it requiring binding.
>
> Would that be feasible?
>
> On Sun, Jan 22, 2023, at 8:36 PM, Larry Garfield wrote:
> > On Sun, Jan 22, 2023, at 11:45 AM, Ollie Read wrote:
> > > Hello all,
> > >
> > > I've created a feature request issue on GitHub (here:
> > > https://github.com/php/php-src/issues/10414), but I have been advised
> > > that it's best to post here.
> > >
> > > What I would like to introduce/suggest, is the ability to create a
> > > closure from a method using the first-class-callable syntax (eg:
> > > MyClass::aMethod(...)), for a non-static method, statically.
> > >
> > > Currently, the following code causes an error.
> > >
> > > ```
> > > class Test {
> > > public function test(): string { return 'test'; }
> > > }
> > >
> > > $closure = Test::test(...);
> > > ```
> > >
> > > I understand why the error is thrown, but, and I'm unsure of the
> > > specifics regarding this, I think we could delay the error until the
> > > closure was called. The reason for this, is that closures can be bound,
> > > so if you followed on from the code above, you could do the following:
> > >
> > > ```
> > > $closure->bindTo(new Test);
> > > $closure();
> > > ```
> > >
> > > The above would bind the closure in $closure to the scope of an object,
> > > which in this case, is the class that the method belongs to.
> > >
> > > The best example I can think, for this, would be when filter a
> > > collection of instances. If you were using a collection library, you
> > > would currently have something like the following:
> > >
> > > ```
> > > $collection->filter(function (Str $string) {
> > > return !$string->empty();
> > > });
> > > ```
> > >
> > > Whereas it would be much nicer to have the following:
> > >
> > > ```
> > > $collection->filter(Str::empty(...));
> > > ```
> > >
> > > In this situation, the collection library would be responsible for
> > > binding the closure to the value it is iterating.
> >
> > So you'd implement this yourself elsewhere?
> >
> > class Str {
> >   public function empty(): bool { ... }
> > }
> >
> > I don't see in this example how this is any better than what is already 
> > currently possible:
> >
> > class Str {
> >   public static function empty(Str $s): bool { ... }
> > }
> >
> > $collection->filter(Str::empty(...));
> >
> > > I have limited experience with PHPs source, and C in general, but my
> > > understanding would be that if we were creating a closure, we would
> > > skip the check for the static method. The code responsible for handling
> > > the closure call would most require some additional functionality to
> > > check if it was bound to a valid instance, returning an error if it
> > > isn't, and then returning an error if it isn't bound at all and the
> > > method isn't static.
> > >
> > > The more I think about it, the more I think this may require a new type
> > > of Closure, or at least a runtime applied interface, to help developers
> > > determine whether a closure was created using first-class-callable
> > > syntax.
> >
> > This is, I think, the important part here, and would be a prerequisite.  
> > Right now there's no way (as far as I know) to differentiate a closure that 
> > is callable from one that would be callable if it were bound to an object.  
> > That's generally not a huge deal in practice as unbound closures are not 
> > often used, but what you're suggesting would make them much more likely.  
> > Also, a static closure cannot be bound, so you cannot just blindly bind 
> > whatever callable you're passed to $this, in your example.  (Besides, 
> > blindly binding a closure to $this sounds like a great security hole.)
> >
> > So for some variant of this to work, I think you'd first need to think 
> > through how to (easily and without dipping into reflection) determine if a 
> > closure object is bindable (static or not) and if it's already bound.  Once 
> > that's figured out, then we can see what, if any, short-hand way to make a 
> > not-yet-bound closure makes sense.  (Which could be FCC syntax or not, I 
> > don't know.)
> >
> > --Larry Garfield
> >
> > --
> > PHP Internals - PHP Runtime Development Mailing List
> > 

Re: [PHP-DEV] Introduce the abiltiy to use the first-call-callable syntax on non-static methods, statically

2023-01-23 Thread Ollie Read
You are absolutely correct. I guess the solution would be to handle it 
differently in this case.

Creating a closure from a static method would be fine, as it creates a static 
closure, but when attempting to create a static closure from a non-static 
method, it would instead return a closure that errors if it isn't bound to an 
appropriate object. You'd most likely want to restrict this to public methods 
only, which would help with the security issues.

There's already a check there that throws an error, so we can already tell the 
difference there, but the tricky part will be in the returned closure. Perhaps 
something like "BindingClosure" that throws the static error when attempting to 
call it unbound, or better yet, a more descriptive error about it requiring 
binding.

Would that be feasible?

On Sun, Jan 22, 2023, at 8:36 PM, Larry Garfield wrote:
> On Sun, Jan 22, 2023, at 11:45 AM, Ollie Read wrote:
> > Hello all,
> >
> > I've created a feature request issue on GitHub (here: 
> > https://github.com/php/php-src/issues/10414), but I have been advised 
> > that it's best to post here.
> >
> > What I would like to introduce/suggest, is the ability to create a 
> > closure from a method using the first-class-callable syntax (eg: 
> > MyClass::aMethod(...)), for a non-static method, statically. 
> >
> > Currently, the following code causes an error.
> >
> > ```
> > class Test {
> > public function test(): string { return 'test'; }
> > }
> > 
> > $closure = Test::test(...);
> > ```
> >
> > I understand why the error is thrown, but, and I'm unsure of the 
> > specifics regarding this, I think we could delay the error until the 
> > closure was called. The reason for this, is that closures can be bound, 
> > so if you followed on from the code above, you could do the following:
> >
> > ```
> > $closure->bindTo(new Test);
> > $closure();
> > ```
> >
> > The above would bind the closure in $closure to the scope of an object, 
> > which in this case, is the class that the method belongs to.
> >
> > The best example I can think, for this, would be when filter a 
> > collection of instances. If you were using a collection library, you 
> > would currently have something like the following:
> >
> > ```
> > $collection->filter(function (Str $string) {
> > return !$string->empty();
> > });
> > ```
> >
> > Whereas it would be much nicer to have the following:
> >
> > ```
> > $collection->filter(Str::empty(...));
> > ```
> >
> > In this situation, the collection library would be responsible for 
> > binding the closure to the value it is iterating.
> 
> So you'd implement this yourself elsewhere?
> 
> class Str {
>   public function empty(): bool { ... }
> }
> 
> I don't see in this example how this is any better than what is already 
> currently possible:
> 
> class Str {
>   public static function empty(Str $s): bool { ... }
> }
> 
> $collection->filter(Str::empty(...));
> 
> > I have limited experience with PHPs source, and C in general, but my 
> > understanding would be that if we were creating a closure, we would 
> > skip the check for the static method. The code responsible for handling 
> > the closure call would most require some additional functionality to 
> > check if it was bound to a valid instance, returning an error if it 
> > isn't, and then returning an error if it isn't bound at all and the 
> > method isn't static.
> >
> > The more I think about it, the more I think this may require a new type 
> > of Closure, or at least a runtime applied interface, to help developers 
> > determine whether a closure was created using first-class-callable 
> > syntax.
> 
> This is, I think, the important part here, and would be a prerequisite.  
> Right now there's no way (as far as I know) to differentiate a closure that 
> is callable from one that would be callable if it were bound to an object.  
> That's generally not a huge deal in practice as unbound closures are not 
> often used, but what you're suggesting would make them much more likely.  
> Also, a static closure cannot be bound, so you cannot just blindly bind 
> whatever callable you're passed to $this, in your example.  (Besides, blindly 
> binding a closure to $this sounds like a great security hole.)
> 
> So for some variant of this to work, I think you'd first need to think 
> through how to (easily and without dipping into reflection) determine if a 
> closure object is bindable (static or not) and if it's already bound.  Once 
> that's figured out, then we can see what, if any, short-hand way to make a 
> not-yet-bound closure makes sense.  (Which could be FCC syntax or not, I 
> don't know.)
> 
> --Larry Garfield
> 
> -- 
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
> 
> 

---
Best Regards,
*Ollie Read*


Re: [PHP-DEV] [RFC] Path to Saner Increment/Decrement operators

2023-01-23 Thread G. P. B.
On Fri, 20 Jan 2023 at 19:44, Jordan LeDoux  wrote:

> I don't see a section in the RFC about JIT or anything related to OpCache,
> but I know from experience with the Operator Overloads RFC that there are
> several architecture specific assembly optimizations for ++ and --. Have
> these been considered, and how will they be impacted?
>

The only assembly specific code is for integer increments/decrements, as
those are not affected by this RFC there is no impact to them.

Best regards,

George P. Banyard


Re: [PHP-DEV] [RFC] Path to Saner Increment/Decrement operators

2023-01-23 Thread G. P. B.
On Fri, 20 Jan 2023 at 18:28, Mark Baker  wrote:

> The documentation page consistently uses the word Increment and
> Decrement, not Add 1 and Subtract 1.
>
> Developers who read the documentation should be aware of the Perl
> convention when dealing with alphabetic strings, and should expect that
> behaviour. Alphanumeric strings are certainly more problematic, less
> well documented, and less well understood, and I'll agree that they're
> inconsistent in their behaviour.
>

The PHP documentation has never been the source of truth about the PHP
implementation,
if it was dynamics properties should have been removed without any notice
as until them being deprecated there was no documentation.
So arguing *something* should behave a certain way because the docs are
written in a certain way holds no value to me.
The state of the PHP docs could certainly be improved, as it is blatantly
lying at various core sections.

However, the whole point of this RFC is to *remove* cognitive burden for
developers, so they don't even need to be aware of this "feature" and not
get surprised when it kicks in.
Moreover, by your logic, you wouldn't care if we removed support for
alphanumeric strings and only let the PERL increment kick in for purely
alphabetical.
While convenient for you, someone might actually use this feature on
alphanumeric strings, and we're back to "why is my use case being removed
while that other just as weird one remains".

I even went initially for such a proposal (see previous revision [1]),
however, I realized this provides minimal benefit as it doesn't reduce at
all the cognitive burden or the overall design specification of the
language.



> Deprecating the Increment operator for strings will create extra work
> for me, will affect many of the users of my library, and I'm certain it
> will also have a performance impact on the library (replacing that
> operation with a more expensive function call for alpha increments, but
> still having the operation for numeric increments). So yes, I am willing
> to die on this hill because that deprecation will have a very direct and
> adverse affect on my work.
>

If the issue is about performance, it is possible to enhance the optimizer
to inline those two functions (something the optimizer already attempts to
do for userland functions [2]).
The other aspect goes back to the typical conundrum: Do we think PHP is in
decline?
 - If yes, then not doing breaking changes and catering to legacy projects
is definitely the course of action to take.
 - If no, improving PHP for the next generation of developers and software,
so that it is easier to learn and reason about, should be the course of
action to take.

As I personally think we are in the second situation, that's why I'm
tackling this subject in this manner.
It's the same belief that made us deprecate dynamic properties, convert
warnings to Errors, etc.

Now, if we are in the former case, then you are totally justified, and I
probably should find another job as I see no point in not improving the
overall language semantics.

George P. Banyard

[1] https://wiki.php.net/rfc/saner-inc-dec-operators?rev=1669977388
[2] See zend_try_inline_call() function