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: 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