Re: [RFC] Operator Overrides -- Lite Edition

From: Date: Sat, 29 Jun 2024 09:01:21 +0000
Subject: Re: [RFC] Operator Overrides -- Lite Edition
References: 1 2 3 4  Groups: php.internals 
Request: Send a blank email to [email protected] to get a copy of this message
On Sat, Jun 29, 2024, at 02:13, Jordan LeDoux wrote:
> 
> 
> On Fri, Jun 28, 2024 at 12:55 PM Rob Landers <[email protected]> wrote:
>> __
>> 
>> 
>>> 3. The private/protected distinction is fairly meaningless for the functions that
>>> implement overloads, because the privacy of the function is ignored completely when it is executed
>>> to evaluate an operator.
>> 
>> Hmm. I like the idea of protected, because it gives a structure to it that is apparent and
>> usable right from the IDE. You just “fill in the blanks” or stick with the default behavior. 
> 
> I do not understand how the visibility has any impact on the usability you are seeking to
> provide.

I guess it depends on what you mean by usability. From a technical standpoint, it has zero
usability, but from a dev-ex standpoint, it has a huge amount of usability.

If we add these as protected methods to the base class, I merely need to write "protected
static function<tab>" in my IDE and I will see all the methods I can write. It also lays
bare "how it works" for a PHP developer without any magic, making it easier to document.

> 
>>> 4. The static distinction is also fairly meaningless, as in PHP there is
>>> no situation possible where an operator overload can occur WITHOUT it operating on objects
>>> themselves.
>> 
>> For this, that is the wrong approach. The actual behavior is on the type, not the instance.
>> The object instances may not even know their value, they merely represent the value.
> 
> A GMP object instance that does not know its value? What are you even talking about? Can you
> show me some code explaining what you mean? I had literally months of this argument for the operator
> overloads RFC, and studied the overload implementations in six other languages as part of writing
> that RFC, I feel like I understand this topic fairly well. But I do not understand what you are
> saying here.

Heh, yeah, it's kinda weird. Let me explain. The GMP class hides its value in a
"private" member (because the value isn't actually a number, but a GMP resource), so
unless the programmer also sets the value to something they have access to, they won't know the
value (but they can always cast $this to a number or operate on it directly). The only way they
could get the value is to cast $this to float, which may lose some precision. The idea here is to
"write the rules" where the value doesn't matter, or if it does, embed that as part
of the rules.

For example, imagine we want to create a Field class, that takes a range for the field and keeps the
value in the field. It might look something like this:

class IntField {
  public function __construct(private int $max, int $value) {
    parent::construct($value, 10);
  }
  public function add($left, $right): self {
    // todo: guard that left can be added to right -- ie, both are integers
    $result = parent::add($left, $right);
    if ($result >= $this->max) return new IntField($this->max, $result % $this->max);
    return new IntField($this->max, $result);
  }
  // todo: remaining implementation
} 

I actually had a bit of a long-thought about it, and I think this is simpler (both to implement and
to use) than the traditional approach, and more powerful. With the more traditional approach, how do
define communitive rules? You are bound by traditional mathematics, more-or-less. From working in
cryptography, a long time ago now, I can say that there are non-communitive rings where having
access to both "left" and "right" can allow you to handle this quite well.

>  
>> 
>>> 6. The comparable function you propose doesn't actually have an
>>> operator it corresponds to. There is no operator in PHP for "is the left value comparable with
>>> the right value". There are operators for comparisons themselves, which I assume you meant, but
>>> a bool is insufficient as a return type for that.
>> 
>> In the engine, there’s just a compare function for internal overrides. So we just check
>> that everyone agrees that the two objects are comparable and then pass it on to “business as
>> usual.”
> 
>  I'm aware of how the compare handler for class entries and zend_compare interact. What I
> am saying is that your design is insufficient for <=>. You cannot return false
> from this method to mean uncomparable, and true to mean comparable. The zend_compare
> function can validly return 0 or -1, with the -1 being used for both less than OR greater than
> because the operands are reordered to always be a less than comparison. Then 1, which normally is
> used for greater than, is used to mean uncomparable.

Ah, I mean that it calls this as a guard, before ever doing a comparison, not that this output will
be used for comparison itself. This is deliberate, to keep it simple. If I get feedback that
comparison should be implemented vs. a guard for comparison, I'd be happy to add it.

> As you are proposing this without any genuine expectation you can pass it, this will be the
> last energy I will invest into helping.

I didn't mean it how I think you are taking it. To expand a bit on what I meant, "we"
(as in people who want this feature, like myself) can only create RFCs for it. Maybe one day, the
voters will change their mind, "we" will find an implementation they agree with, or
they'll forget to vote "no" while enough people vote "yes." So, yes, I
genuinely want this feature and I want to propose a feature that works and is the best I can come up
with; at the same time, I don't expect it to pass, but I do hope that negative feedback will
drive the feature to a compromise or solution that works. The only way to get there is by failing.

— Rob


Thread (27 messages)

« previous php.internals (#124014) next »