Re: [RFC] Operator Overrides -- Lite Edition

From: Date: Sat, 29 Jun 2024 09:05:20 +0000
Subject: Re: [RFC] Operator Overrides -- Lite Edition
References: 1 2 3 4 5  Groups: php.internals 
Request: Send a blank email to internals+get-124015@lists.php.net to get a copy of this message
On Sat, Jun 29, 2024, at 11:01, Rob Landers wrote: > On Sat, Jun 29, 2024, at 02:13, Jordan LeDoux wrote: >> >> >> On Fri, Jun 28, 2024 at 12:55 PM Rob Landers <rob@bottled.codes> 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: sigh: not enough coffee again and I saw the blunder as soon as I sent it.. Here's the more correct implementation. class IntField { public function __construct(private int $max, int $value) { parent::construct($value, 10); } protected static 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 >= $left->max) return new IntField($left->max, $result % $left->max); return new IntField($left->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 — Rob

« previous php.internals (#124015) next »