Re: [PHP-DEV] Custom object equality

2023-10-23 Thread Jordan LeDoux
On Mon, Oct 23, 2023 at 10:20 AM Dik Takken  wrote:

> On 23-10-2023 18:34, Larry Garfield wrote:
> >
> > Jordan's RFC explained in detail why interfaces are not viable, which is
> why we have to use magic methods (with or without a special keyword)
> instead:
> >
> >
> https://wiki.php.net/rfc/user_defined_operator_overloads#why_not_interfaces
> >
> > (Seriously, it has an extensive FAQ.  It's one of the more detailed and
> supported RFCs we've seen.)
> >
>
> Yes, I know the RFC, it's a great piece of work! The use of interfaces
> as mentioned in this RFC is however completely different from what
> Pierre and I are talking about. If I understand Pierre correctly, that
> is. The suggestion to include interfaces simply meant to allow freedom
> of choice. Choice between using an operator (`==`) or calling the
> equivalent method on the object (`->equals()`). That may get more people
> on board with operator overloading.
>
> Regards,
> Dik
>
>
I don't quite follow. The interface would cause the engine to use the
result of an `equals()` function on the object if it implements an
interface as part of `zend_compare`? Internally there is no `==` function,
there is only the equivalent of `<=>`. To implement it ONLY for `==` would
require a trapdoor of some kind in the `do_operation` handler that would
also affect the way the existing extensions work, such as the `DateTime`
class which implements a custom handler for the `compare` handler on the
zend class entry.

This might be easier to do once a few comparison improvements to separate
"comparable" and "equatable" are done, but the PR I submitted two years ago
to handle that got kind of mired in bike shedding about the implementation
and I lost interest in continuing to push it.

Implementing the compare handler for an overload requires adding two new
entries to ZEND_AST_BINARY_OP because the `>` and `<` comparisons have to
be preserved in the AST in order to call the correct object handler. THAT
requires updating OpCache and JIT since all such comparisons are currently
reordered to use `<`, and though I spent quite a while looking at it, I
think Dmitry might be the only person that could really implement that
fully. At least, I never found anyone that had the expertise to actually
help me with it.

Jordan


Re: [PHP-DEV] Custom object equality

2023-10-23 Thread Dik Takken

On 23-10-2023 18:34, Larry Garfield wrote:


Jordan's RFC explained in detail why interfaces are not viable, which is why we 
have to use magic methods (with or without a special keyword) instead:

https://wiki.php.net/rfc/user_defined_operator_overloads#why_not_interfaces

(Seriously, it has an extensive FAQ.  It's one of the more detailed and 
supported RFCs we've seen.)



Yes, I know the RFC, it's a great piece of work! The use of interfaces 
as mentioned in this RFC is however completely different from what 
Pierre and I are talking about. If I understand Pierre correctly, that 
is. The suggestion to include interfaces simply meant to allow freedom 
of choice. Choice between using an operator (`==`) or calling the 
equivalent method on the object (`->equals()`). That may get more people 
on board with operator overloading.


Regards,
Dik

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



Re: [PHP-DEV] Custom object equality

2023-10-23 Thread Larry Garfield
On Mon, Oct 23, 2023, at 3:14 PM, Dik Takken wrote:
> On 18-10-2023 14:50, someniatko wrote:
>> This approach allows combining
>> - no BC break - `~=` is a new syntax which is unavailable in older PHP
>> versions
>> - explicitly showing an intent that objects are compared using a custom
>> comparison, rather than standard PHP one
>> - allow to skip writing boilerplate equals() methods which just forward
>> equals() to the nested objects
>> - standardize such comparisons on the language level
>> 
>> Of course how exactly this operator looks may be changed, `~=` is just an
>> example.
>> 
>> WDYT?
>> 
>> Regards,
>> Illia / someniatko
>> 
>
> One thing to keep in mind is that operator overloading already exists in 
> PHP. And it is already in use in userland PHP too, for example when 
> comparing DateTime objects. The limitation is that it only works for 
> some objects: Those that are implemented in an extension.
>
> To me, the obvious way forward would be to lift this limitation. But... 
> several attempts to do so have failed to pass. People are hesitant to 
> unleash full operator overloading power to PHP developers.
>
> So, perhaps a simplified version of the RFC by Jordan LeDoux, limited to 
> the `==` operator only, would stand a chance? It would allow the 
> community to try their hands on this one (highly valuable) operator 
> overload. PHP 9 is coming and provides a great opportunity.
>
> I also like the idea from Pierre to provide interfaces. Some people 
> prefer an explicit method call over an operator doing magic things, 
> which I fully understand. Perhaps we could allow both?
>
> Regards,
> Dik

I would recommend including ==, <, >, <=, >= all in the initial design, as they 
do interact.  I've said in the past that I'd welcome a reduced-scope version as 
a stepping stone.

Jordan's RFC explained in detail why interfaces are not viable, which is why we 
have to use magic methods (with or without a special keyword) instead:

https://wiki.php.net/rfc/user_defined_operator_overloads#why_not_interfaces

(Seriously, it has an extensive FAQ.  It's one of the more detailed and 
supported RFCs we've seen.)

--Larry Garfield

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



Re: [PHP-DEV] [RFC] [Discussion] Change the edge case of round()

2023-10-23 Thread Saki Takamachi
Hi, Max

This was originally discussed in a pull request. If you're interested in the 
original discussion, check out this pull request.
https://github.com/php/php-src/pull/12268

Regards.

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



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Le 23/10/2023 à 18:11, Saki Takamachi a écrit :

If I understand your use case properly, you should be confused by properties 
with default values that are not constructor-promoted as well ? Am I wrong ? In 
this case, your problem is not with promoted properties ?

If we specify it the way you say, the initial values ​​of the constructor 
arguments will be available even when the constructor is not called.

Such behavior felt a little counterintuitive.


Which then would simply be the same behavior as properties when not 
promoted but declared in the class body instead:


```php

class Foo
{
    public $val = 'abc';
}

$redis_foo = serialize(new Foo());

$foo = unserialize($redis_foo);
var_dump($foo->val);
// string(3) "abc"

```

Right ?

What's the most disturbing in my opinion is that: `class Foo { public 
string $val = 'abc' }` and `class Foo { public function 
__construct(public string $val = 'abc' ) {}}` don't yield the same 
behavior at the time.


Regards,

--

Pierre

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



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Saki Takamachi
> If I understand your use case properly, you should be confused by properties 
> with default values that are not constructor-promoted as well ? Am I wrong ? 
> In this case, your problem is not with promoted properties ?

If we specify it the way you say, the initial values ​​of the constructor 
arguments will be available even when the constructor is not called.

```
class Foo
{
public function __construct()
{
}
}

$foo = serialize(new Foo()); 
// save to redis

 update 

class Foo
{
public function __construct(
public $val = 'abc'
) {
}
}

$foo = unserialize($redis_foo);
var_dump($foo->val);
// string(3) "abc"
// Doesn't it look like the constructor is being called?
```

Such behavior felt a little counterintuitive.

Regards.

Saki

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



Re: [PHP-DEV] [RFC] [Discussion] Change the edge case of round()

2023-10-23 Thread Max Semenik
This sounds like a subtle breakage to a lot of code. Could you elaborate
the motivation for such change? One sentence doesn't seem enough. Also,
have you tried assessing how much existing code might be affected?

On Mon, Oct 23, 2023 at 2:19 PM Saki Takamachi  wrote:

> Sorry, I posted a completely unrelated URL.
>
> Correct url:
> https://wiki.php.net/rfc/change_the_edge_case_of_round
>
> Regards.
>
> Saki
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>

-- 
Best regards,
Max Semenik


Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Le 23/10/2023 à 17:35, Saki Takamachi a écrit :

Hi, Pierre

You may have overlooked the existence of the magic method `__unserialize()`. 
Constructor is not the only way to create instances.

When rebuilding a serialized object, you may need the initial values ​​of 
properties. This can easily happen if you are using rolling updates and using 
Redis. The constructor is not called if `__unserialize()` is called. In this 
case, defining the initial value of a property as an argument to a constructor 
that is never called confuses us.

Regards.

Saki


If I understand your use case properly, you should be confused by 
properties with default values that are not constructor-promoted as well 
? Am I wrong ? In this case, your problem is not with promoted properties ?


Regards,

--

Pierre

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



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Saki Takamachi
Hi, Pierre

You may have overlooked the existence of the magic method `__unserialize()`. 
Constructor is not the only way to create instances.

When rebuilding a serialized object, you may need the initial values ​​of 
properties. This can easily happen if you are using rolling updates and using 
Redis. The constructor is not called if `__unserialize()` is called. In this 
case, defining the initial value of a property as an argument to a constructor 
that is never called confuses us.

Regards.

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



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Le 23/10/2023 à 17:16, Larry Garfield a écrit :

Where this becomes a problem is readonly properties, since those are not 
allowed to have default values.  (That would make them constants with worse 
performance.)  A solution would need to be able to detect that the 
parent::__construct() isn't called, and then call it anyway, or at least 
partially call it.  Unfortunately, I can think of many cases where such a call 
would result in unexpected behavior.

It might be possible to resolve, but it's definitely not simple, and it could 
easily lead to weird behavior.

--Larry Garfield


Thanks for the explanation !

I see, there is no easy answer, yet current state is, in my opinion, 
unintuitive for developers, and eventually unsatisfying when falling in 
this trap.


That's sad that readonly properties make this not trivial. Maybe some 
kind of object construct-post-hook could detect those case and affect 
variables with default values ? I don't know enough PHP internals to 
give a rational answer to this problem through...


Regards,

--

Pierre



Re: [PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Larry Garfield
On Mon, Oct 23, 2023, at 2:18 PM, Pierre wrote:
> Hello internals,
>
> I stumbled upon this behavior, if I write this:
>
> ```php
> class Foo
> {
>      public ?string $prop = null;
>
>      public function __construct(?string $prop = null)
>      {
>      $this->prop = $prop;
>      }
> }
>
> class Bar extends Foo
> {
>      public function __construct(
>      public ?string $bar = null,
>      ) {}
> }
>
> // Echoes nothing, but it works as expected.
> echo (new Bar())->prop;
> ```
>
> It works as intended, but if I replace the `Foo` class using:
>
> ```php
> class Foo
> {
>      public function __construct(
>      public ?string $prop = null,
>      ) {}
> }
> ```
>
> It won't work anymore and I have the following error:
>
> ```
> PHP Warning:  Uncaught Error: Typed property Foo::$prop must not be 
> accessed before initialization in php shell code:9
> ```
>
> If I understand it correctly:
>   - in the first case, default value is attached to the object property, 
> so if I omit its constructor, I have the default,
>   - in the second case, default value is attached to the constructor 
> parameter, and not to the object property, which means that in case the 
> parent constructor is not called in the `Bar` class, `$prop` remains 
> initialized.
>
> It doesn't sound like a bug, but I think that many people would actually 
> expect otherwise: that the constructor promoted property keep their 
> default even when constructor is not explicitly called.
>
> Is there any good reason behind this ? Wouldn't it be best to change 
> this behavior ? Would it be a risk for backward compatibility (my guess 
> is "not that much, probably not a all even") ?

Where this becomes a problem is readonly properties, since those are not 
allowed to have default values.  (That would make them constants with worse 
performance.)  A solution would need to be able to detect that the 
parent::__construct() isn't called, and then call it anyway, or at least 
partially call it.  Unfortunately, I can think of many cases where such a call 
would result in unexpected behavior.

It might be possible to resolve, but it's definitely not simple, and it could 
easily lead to weird behavior.

--Larry Garfield

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



Re: [PHP-DEV] Custom object equality

2023-10-23 Thread Dik Takken

On 18-10-2023 14:50, someniatko wrote:

This approach allows combining
- no BC break - `~=` is a new syntax which is unavailable in older PHP
versions
- explicitly showing an intent that objects are compared using a custom
comparison, rather than standard PHP one
- allow to skip writing boilerplate equals() methods which just forward
equals() to the nested objects
- standardize such comparisons on the language level

Of course how exactly this operator looks may be changed, `~=` is just an
example.

WDYT?

Regards,
Illia / someniatko



One thing to keep in mind is that operator overloading already exists in 
PHP. And it is already in use in userland PHP too, for example when 
comparing DateTime objects. The limitation is that it only works for 
some objects: Those that are implemented in an extension.


To me, the obvious way forward would be to lift this limitation. But... 
several attempts to do so have failed to pass. People are hesitant to 
unleash full operator overloading power to PHP developers.


So, perhaps a simplified version of the RFC by Jordan LeDoux, limited to 
the `==` operator only, would stand a chance? It would allow the 
community to try their hands on this one (highly valuable) operator 
overload. PHP 9 is coming and provides a great opportunity.


I also like the idea from Pierre to provide interfaces. Some people 
prefer an explicit method call over an operator doing magic things, 
which I fully understand. Perhaps we could allow both?


Regards,
Dik

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



[PHP-DEV] Constructor promoted property and default value

2023-10-23 Thread Pierre

Hello internals,

I stumbled upon this behavior, if I write this:

```php
class Foo
{
    public ?string $prop = null;

    public function __construct(?string $prop = null)
    {
    $this->prop = $prop;
    }
}

class Bar extends Foo
{
    public function __construct(
    public ?string $bar = null,
    ) {}
}

// Echoes nothing, but it works as expected.
echo (new Bar())->prop;
```

It works as intended, but if I replace the `Foo` class using:

```php
class Foo
{
    public function __construct(
    public ?string $prop = null,
    ) {}
}
```

It won't work anymore and I have the following error:

```
PHP Warning:  Uncaught Error: Typed property Foo::$prop must not be 
accessed before initialization in php shell code:9

```

If I understand it correctly:
 - in the first case, default value is attached to the object property, 
so if I omit its constructor, I have the default,
 - in the second case, default value is attached to the constructor 
parameter, and not to the object property, which means that in case the 
parent constructor is not called in the `Bar` class, `$prop` remains 
initialized.


It doesn't sound like a bug, but I think that many people would actually 
expect otherwise: that the constructor promoted property keep their 
default even when constructor is not explicitly called.


Is there any good reason behind this ? Wouldn't it be best to change 
this behavior ? Would it be a risk for backward compatibility (my guess 
is "not that much, probably not a all even") ?


Regards,

--
Pierre

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



Re: [PHP-DEV] [RFC] [Discussion] Change the edge case of round()

2023-10-23 Thread Saki Takamachi
Sorry, I posted a completely unrelated URL.

Correct url:
https://wiki.php.net/rfc/change_the_edge_case_of_round

Regards.

Saki

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



[PHP-DEV] [RFC] [Discussion] Change the edge case of round()

2023-10-23 Thread Saki Takamachi
Hi, internals

I would like to start the discussion for my RFC "Change the edge case of 
round()”.
https://wiki.php.net/rfc/change_the_edge_case_of_round 


Regards.

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