Re: [PHP-DEV] [RFC] [Discussion] Clone with

2023-04-25 Thread Alexandru Pătrănescu
On Wed, Apr 26, 2023 at 3:25 AM Larry Garfield 
wrote:

> On Tue, Apr 25, 2023, at 11:23 AM, Nicolas Grekas wrote:
>
> > What about using a real closure to define the scope we need for cloning?
> > That closure would take the cloned instance as argument to allow
> > manipulating it at will.
>
> I believe someone mentioned that one previously in the thread.


Yes, Nicolas mentioned me.
I wanted to get back myself to discussing this topic more as well and find
a better solution but didn't get yet time for it.


>   The problem is that the closure would run in the scope of the object,
> not the scope of the caller.  That means if called outside the object, it
> would allow modifying private or protected properties.  The itemized list
> of values (whether an array or named-args style) would allow the engine to
> enforce access restrictions, which is a desireable feature.
>

As far as I can see, Nicolas was able to find a solution to this problem
and so far I like it:
The closure is running in the current scope where it is defined and not in
the scope of the cloned object. The cloned object is passed as the single
parameter to the closure.

The suggested clone signature for a class T would be:
- clone(T $object, callable(T $clone)): T; // calling clone as a function
- clone T $object with callable(T $clone): T; // calling clone as a
language construct
Alternatively, we can have also:
- clone T, callable(T $clone); // without "with" keyword
And improve it to allow even multiple closures to be executed:
- clone(T $object, ...callable(T $clone)): T;
- clone T $object, ...callable(T $clone): T;

IMHO, I think we should support both syntaxes.

The main reason I wanted to get back to this proposal is because > 90% of a
developer's job is to read code and the most trouble is following state
modifications of a variable.

When that variable to be investigated is a property, so far it was simple
to look for "->propertyName = ".
Editors would easily and clearly highlight all the write access statements
or lines (Alt+F7 in PhpStorm). I can't figure out what would be highlighted
in the non-closure syntax, especially the one with an array.

Thanks,
Alex


Re: [PHP-DEV] [RFC] [Discussion] Clone with

2023-04-25 Thread Larry Garfield
On Tue, Apr 25, 2023, at 11:23 AM, Nicolas Grekas wrote:

> What about using a real closure to define the scope we need for cloning?
> That closure would take the cloned instance as argument to allow
> manipulating it at will.

I believe someone mentioned that one previously in the thread.  The problem is 
that the closure would run in the scope of the object, not the scope of the 
caller.  That means if called outside the object, it would allow modifying 
private or protected properties.  The itemized list of values (whether an array 
or named-args style) would allow the engine to enforce access restrictions, 
which is a desireable feature.

--Larry Garfield

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



Re: [PHP-DEV] Final anonymous classes

2023-04-25 Thread Juliette Reinders Folmer

On 24-4-2023 12:28, Daniil Gentili wrote:

Hi all,

I've submitted https://github.com/php/php-src/pull/11126 to add 
support for final anonymous classes, though as noted by iluuu1994, it 
would probably make more sense to just make all anonymous classes 
final by default, what do you think?


Daniil Gentili.



I always though anonymous class where `final` by nature. The fact that 
that hack to extend them works, seems iffy at best.


For what it's worth, I'd be in favour of making the default behaviour 
for anonymous classes `final` without the need to add a `final` keyword.


For those edge-cases which would be broken by that change, I wonder if 
support to opt-out could be added via an `#[AllowAliasing]` attribute ?


Re: [PHP-DEV] [Discussion] Callable types via Interfaces

2023-04-25 Thread Larry Garfield
On Tue, Apr 25, 2023, at 6:20 PM, Michał Marcin Brzuchalski wrote:

> Personally I don't like this way of shaping callable types. Given examples
> are really confusing me. Call of a castTo() with argument representing an
> interface with a method is confusing as the method magically appears on a
> closure without explicit binding to it! What if an interface has more than
> one method? What if I wanna choose which one?

Multi-method interfaces would be explicitly disallowed and trigger an Error.  
If providing only a single "method", then there's no logical way for it to 
satisfy a multi-method interface.  But there are ample single-method interfaces 
around PHPlandia.  And a single-method interface has no ambiguity about which 
method the closure corresponds to.

--Larry Garfield

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



Re: [PHP-DEV] Final anonymous classes

2023-04-25 Thread Claude Pache



> Le 25 avr. 2023 à 15:46, Nicolas Grekas  a 
> écrit :
> 
> 
> Because they conceptually don't create a new type, I wonder if (final)
> anonymous classes could be allowed to extend final classes? In order to not
> allow hacking around and still create a type with class_alias(), we should
> forbid aliasing final anonymous classes IMHO. Then we could have this
> discussion about allowing finally anonymous classes to extend final
> classes. That'd be really useful in many situations where "final" is
> preventing end users from achieving what they want.


That would violate the very definition of `final`, which may be interpreted as 
“final implementation” as much as “final type”?

If your goal is to have a proxy, I wonder whether it would be more appropriate 
to design a proper way to define a proxy around an existing object, rather than 
hacking around class inheritance?


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



Re: [PHP-DEV] [Discussion] Callable types via Interfaces

2023-04-25 Thread Michał Marcin Brzuchalski
Hi Nicolas,

wt., 25 kwi 2023, 19:00 użytkownik Nicolas Grekas <
nicolas.grekas+...@gmail.com> napisał:

> Hi all,
>
>
> https://wiki.php.net/rfc/allow_casting_closures_into_single-method_interface_implementations
> >
> >
> https://wiki.php.net/rfc/allow-closures-to-declare-interfaces-they-implement
> > https://wiki.php.net/rfc/structural-typing-for-closures
>
>
> Thanks Larry for the nice introduction to those ideas.
>
> Personally, I feel like going with adding Closure::castTo() might provide
> the most immediate benefit. I expanded the rationale on the corresponding
> RFC and added more examples. I'd appreciate it if all of you reading could
> have another look to see if that helps to better understand the proposal.
>
> strtr(...)->castTo(TranslatableInterface::class) is one example of RFC #1
> function ($message, $parameters) implements TranslatableInterface is RFC #2
>
> Both RFCs nicely combine together to cover many cases of typed callabled.
>
> Then RFC#3 is a bit more adventurous (according to our understanding) but
> still desirable as it's essentially about allowing the engine to
> tentatively call castTo() from RFC#1 when a closure is passed as argument
> while an interface is expected.
>

Personally I don't like this way of shaping callable types. Given examples
are really confusing me. Call of a castTo() with argument representing an
interface with a method is confusing as the method magically appears on a
closure without explicit binding to it! What if an interface has more than
one method? What if I wanna choose which one?

For me personally this goes into wrong direction.

Cheers,
Michał Marcin Brzuchalski

>


Re: [PHP-DEV] [Discussion] Callable types via Interfaces

2023-04-25 Thread Nicolas Grekas
Hi all,

https://wiki.php.net/rfc/allow_casting_closures_into_single-method_interface_implementations
>
> https://wiki.php.net/rfc/allow-closures-to-declare-interfaces-they-implement
> https://wiki.php.net/rfc/structural-typing-for-closures


Thanks Larry for the nice introduction to those ideas.

Personally, I feel like going with adding Closure::castTo() might provide
the most immediate benefit. I expanded the rationale on the corresponding
RFC and added more examples. I'd appreciate it if all of you reading could
have another look to see if that helps to better understand the proposal.

strtr(...)->castTo(TranslatableInterface::class) is one example of RFC #1
function ($message, $parameters) implements TranslatableInterface is RFC #2

Both RFCs nicely combine together to cover many cases of typed callabled.

Then RFC#3 is a bit more adventurous (according to our understanding) but
still desirable as it's essentially about allowing the engine to
tentatively call castTo() from RFC#1 when a closure is passed as argument
while an interface is expected.

We're now wondering if we should start spending time on prototype
implementations for #1 and/or #2, and #3 in this order. Should we consider
a preliminary vote on the topic?

Nicolas


Re: [PHP-DEV] [RFC] [Discussion] Clone with

2023-04-25 Thread Nicolas Grekas
Hi again,

Quite some time after mentioning the "clone with" construct the first time
> (at the end of the
> https://wiki.php.net/rfc/write_once_properties#run-time_behaviour
> section),
> finally I managed to create a working implementation for this feature which
> would make it possible to properly modify readonly properties
> while simplifying how we write "wither" methods:
> https://wiki.php.net/rfc/clone_with
>

As mentioned in another thread, I'd like to make an alternative proposal
for the syntax.
Alex talked about it already but I think it deserves more attention.

What about using a real closure to define the scope we need for cloning?
That closure would take the cloned instance as argument to allow
manipulating it at will.

Internally, the engine would "just" call that closure just after calling
__clone() if it's defined.

This could look like this:
$c = clone $a with $closure;

or maybe we could skip introducing a new keyword and go for something that
looks like a function call:
$c = clone($a, $closure);

I've adapted your examples from the RFC using the latter and here is how
they could look like:

The “wither” method copy-pasted from Diactoros:
class Response implements ResponseInterface {
public readonly int $statusCode;
public readonly string $reasonPhrase;
// ...
public function withStatus($code, $reasonPhrase = ''): Response
{
return clone($this, fn ($clone) => [
$clone->statusCode = $code,
$clone->reasonPhrase = $reasonPhrase,
]);
}
// ...
}

The property name expressions:
class Foo {
private $a;
private $b;
private $c;
/**
* @param array $properties
*/
public function withProperties(array $properties) {
return clone($this, function ($clone) use ($properties) {
foreach ($properties as $name => $value) {
$clone->$name = $value;
}
});
}
}

Linking the cloned instance to the original one:
class LinkedObject {
public function __construct(
private readonly LinkedObject $next,
private readonly int $number
) {
$this->number = 1;
}
public function next(): LinkedObject {
return clone($this, fn ($clone) => [
$clone->number = $clone->number + 1,
$this->next = $clone,
]);
}
}

All these look pretty neat to me, and they come with no new syntax but a
simple call-like clone() statement.

Scope semantics remain the same as usual, so we already know how to
interpret that aspect.

Does that make sense to you?

Nicolas


Re: [PHP-DEV] [RFC] [Discussion] Clone with

2023-04-25 Thread Nicolas Grekas
Hi Mate,

Quite some time after mentioning the "clone with" construct the first time
> (at the end of the
> https://wiki.php.net/rfc/write_once_properties#run-time_behaviour
> section),
> finally I managed to create a working implementation for this feature which
> would make it possible to properly modify readonly properties
> while simplifying how we write "wither" methods:
> https://wiki.php.net/rfc/clone_with
>

Thanks for working on this, we definitely need improvements on the topic.
Thanks also for mentioning my proposal and for the comparison analysis,
that's really helpful.

Quoting from the RFC:
> One cannot control whether $this should really be cloned: e.g. if a
property should only be modified based on certain conditions (e.g.
validation), the object would potentially be cloned in vain, resulting in a
performance loss.

Returning a clone or the same instance depending e.g. on some validation is
usually an abstraction leak. It's a leak because it allows knowing internal
implementation details by comparing the identity of the resulting objects.
Since the PHP community is leaning towards more strictness and better
abstractions, I think this point is actually a win for my proposal: it'd
naturally close the loophole in wither-based abstractions. See
https://3v4l.org/02IVc#v8.2.5 if what I mean is unclear.

> Sometimes one also needs access to the original instance, but doing so
would only be possible via workarounds (e.g. by introducing $that or a
similar construct).

Here is how we would achieve this under my proposal (adapting from your
example):
class LinkedObject {
/*...*/

public function next(): static {
$clone = $this->prepareNext();
$clone->next = $this;

return $clone;
}

private clone function prepareNext(): static {
$this->number++;
unset($this->next);

return $this;
}
}

As you can see, this works by *not* using the clone keyword on the public
method. And this makes me realize that what you see as an advantage ("it
could be made part of the interface contract") might actually be a
drawback, by forcing a coupling between a contract and an implementation.
That's what you mean also with your last sentence on your analyses.

And that kills my proposal, RIP :)
But I have another proposal I'm sending separately.

Nicolas


Re: [PHP-DEV] Final anonymous classes

2023-04-25 Thread Larry Garfield
On Tue, Apr 25, 2023, at 1:21 PM, Ilija Tovilo wrote:
> Hi Claude
>
>> > Hi all,
>> >
>> > I've submitted https://github.com/php/php-src/pull/11126 to add support 
>> > for final anonymous classes, though as noted by iluuu1994, it would 
>> > probably make more sense to just make all anonymous classes final by 
>> > default, what do you think?
>>
>> Extending an anonymous class is indeed possible (https://3v4l.org/pDFTL), 
>> but it is a hack as best. If someone wants a non-final class, could they not 
>> write a non-anonymous one? As a bonus, they wouldn’t need to instantiate the 
>> class before referencing it.
>
> Indeed. The argument was that, if you need to give the anonymous class
> a dedicated name through an alias to extend it, you might as well
> declare a named class in the first place.
>
> In case somebody finds benefit in making anonymous classes open, it
> seems more sensible to make them opt into openness, rather than
> applying this behavior to all anonymous classes that are used as final
> 99.9% of the time. Although I really don't think that is necessary.
>
> Ilija

I agree, but that would then require adding some kind of "non-final" keyword 
for anon classes to opt back out of finalness.  That's an extra complication I 
don't see as worth the effort to think through.

Until this thread it hadn't even occurred to me that you could extend an anon 
class at all, so the issue never came up.  And the apparent way to do so 
involves eval(), so I'm already afraid of it.  Given how edge-casey this is, 
I'd be inclined to just leave it be.

--Larry Garfield

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



Re: [PHP-DEV] Final anonymous classes

2023-04-25 Thread Nicolas Grekas
Hi all,

> > I've submitted https://github.com/php/php-src/pull/11126 to add support
> for final anonymous classes, though as noted by iluuu1994, it would
> probably make more sense to just make all anonymous classes final by
> default, what do you think?
> >
> > Extending an anonymous class is indeed possible (https://3v4l.org/pDFTL),
> but it is a hack as best. If someone wants a non-final class, could they
> not write a non-anonymous one? As a bonus, they wouldn’t need to
> instantiate the class before referencing it.
>
> Indeed. The argument was that, if you need to give the anonymous class
> a dedicated name through an alias to extend it, you might as well
> declare a named class in the first place.
>
> In case somebody finds benefit in making anonymous classes open, it
> seems more sensible to make them opt into openness, rather than
> applying this behavior to all anonymous classes that are used as final
> 99.9% of the time. Although I really don't think that is necessary.
>

Fun fact: I wrote test code that extends anonymous classes recently.
The typical test case is like this:

$obj = new class() {
public array $foo;
};
$proxy = $this->createLazyGhost($obj::class, fn () => null);


And createLazyGhost() generates a proxy class and returns an instance of
it, see
https://github.com/symfony/symfony/blob/1f8c5928a1445378eacbaf5b7e1636fdfa8610ed/src/Symfony/Component/VarExporter/Tests/LazyGhostTraitTest.php#L415-L438

Admittedly this is for convenience in writing test cases, but convenience
is what many RFCs are about :)

But anyway, there is a related idea I've had in my mind about anonymous
classes that I'd like to throw in that conversation:

Because they conceptually don't create a new type, I wonder if (final)
anonymous classes could be allowed to extend final classes? In order to not
allow hacking around and still create a type with class_alias(), we should
forbid aliasing final anonymous classes IMHO. Then we could have this
discussion about allowing finally anonymous classes to extend final
classes. That'd be really useful in many situations where "final" is
preventing end users from achieving what they want.

Nicolas


Re: [PHP-DEV] Final anonymous classes

2023-04-25 Thread Ilija Tovilo
Hi Claude

> > Hi all,
> >
> > I've submitted https://github.com/php/php-src/pull/11126 to add support for 
> > final anonymous classes, though as noted by iluuu1994, it would probably 
> > make more sense to just make all anonymous classes final by default, what 
> > do you think?
>
> Extending an anonymous class is indeed possible (https://3v4l.org/pDFTL), but 
> it is a hack as best. If someone wants a non-final class, could they not 
> write a non-anonymous one? As a bonus, they wouldn’t need to instantiate the 
> class before referencing it.

Indeed. The argument was that, if you need to give the anonymous class
a dedicated name through an alias to extend it, you might as well
declare a named class in the first place.

In case somebody finds benefit in making anonymous classes open, it
seems more sensible to make them opt into openness, rather than
applying this behavior to all anonymous classes that are used as final
99.9% of the time. Although I really don't think that is necessary.

Ilija

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



Re: [PHP-DEV] Request for RFC Karma - Enum value semantics proposal

2023-04-25 Thread Tim Düsterhus

Hi

On 4/25/23 14:54, Garet Claborn wrote:

I am requesting RFC karma to post the present version of an RFC made in
response to the GitHub issue found at
https://github.com/php/php-src/issues/9208


You should have already been granted RFC karma yesterday by derick, he 
told me that the Wiki would send a notification.


Can you check whether you are already able to create the RFC page and if 
or if not you received an automated email about the permission adjustment?


Best regards
Tim Düsterhus

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



[PHP-DEV] Request for RFC Karma - Enum value semantics proposal

2023-04-25 Thread Garet Claborn
Relating to the existing thread in my introduction:
Re: [PHP-DEV] Introduction - SuitespaceRnD

I am requesting RFC karma to post the present version of an RFC made in
response to the GitHub issue found at
https://github.com/php/php-src/issues/9208

Though any guidance or contributions from those more familiar with this
portion of the codebase is more than welcome; we are happy to assign work
implementing this from our end. We would like to gauge interest, feedback
and any brainstorming prior to beginning work in earnest.

Thanks,
Garet