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