On Sat, Sep 14, 2024 at 11:51 PM Jordan LeDoux <jordan.led...@gmail.com> wrote:
> Hello internals, > > This discussion will use my previous RFC as the starting point for > conversation: https://wiki.php.net/rfc/user_defined_operator_overloads > > There has been discussion on list recently about revisiting the topic of > operator overloads after the previous effort which I proposed was declined. > There are a variety of reasons, I think, this is being discussed, both on > list and off list. > > 1. As time has gone on, more people have come forward with use cases. > Often they are use cases that have been mentioned before, but it has become > more clear that these use cases are more common than was suggested > previously. > > 2. Several voters, contributors, and participants have had more time > (years now) to investigate and research some of the related issues, which > naturally leads to changes in opinion or perspective. > > 3. PHP has considered and been receptive toward several RFCs since my > original proposal which update the style of PHP in ways which are congruent > with the KIND of language that has operator overloads. > > I mentioned recently that I would not participate in another operator > overload RFC unless I felt that the views of internals had become more > receptive to the topic, and after some discussion with several people > off-list, I feel that it is at least worth discussing for the next version. > > Operator overloads has come up as a missing feature in several discussions > on list since the previous proposal was declined. This includes: > > [RFC] [Discussion] Support object type in BCMath [1] > > Native decimal scalar support and object types in BcMath [2] > > Custom object equality [3] > > pipes, scalar objects and on? [4] > > [RFC][Discussion] Object can be declared falsifiable [5] > > The request to support comparison operators (>, >=, ==, !=, <=, <, <=>) > has come up more frequently, but particularly in discussion around linear > algebra, arbitrary precision mathematics, and dimensional numbers (such as > currency or time), the rest of the operators have also come up. > > Typically, these use cases are themselves very niche, but the capabilities > operator overloads enable would be much more widely used. From discussion > on list, it seems likely that very few libraries would need to implement > operator overloads, but the libraries that do would be well used and thus > MANY devs would be consumers of operator overloads. > > I want to discuss what changes to the previous proposal people would be > seeking, and why. The most contentious design choice of the previous > proposal was undoubtedly the `operator` keyword and the decision to make > operator overload implementations distinct from normal magic methods. For > some of the voters who voted yes on the previous RFC, this was a "killer > feature" of the proposal, while for some of the voters who voted no it was > the primary reason they were against the feature. > > There are also several technical and tangentially related items that are > being worked on that would be necessary for operator overloads (and were > originally included in my implementation of the previous RFC). This > includes: > > 1. Adding a new opcode for LARGER and LARGER_OR_EQUAL so that operand > position can be preserved during ALL comparisons. > > 2. Updating ZEND_UNCOMPARABLE such that it has a value other than -1, 0, > or 1 which are typically reserved during an ordering comparison. > > 3. Allowing values to be equatable without also being orderable (such as > with matrices, or complex numbers). > > These changes could and should be provided independent of operator > overloads. Gina has been working on a separate RFC which would cover all > three of these issues. You can view the work-in-progress on that RFC here: > https://github.com/Girgias/php-rfcs/blob/master/comparison-equality-semantics.md > > I hope to start off this discussion productively and work towards > improving the previous proposal into something that voters are willing to > pass. To do that, I think these are the things that need to be discussed in > this thread: > > 1. Should the next version of this RFC use the `operator` keyword, or > should that approach be abandoned for something more familiar? Why do you > feel that way? > > 2. Should the capability to overload comparison operators be provided in > the same RFC, or would it be better to separate that into its own RFC? Why > do you feel that way? > > 3. Do you feel there were any glaring design weaknesses in the previous > RFC that should be addressed before it is re-proposed? > > 4. Do you feel that there is ANY design, version, or implementation of > operator overloads possible that you would support and be in favor of, > regardless of whether it matches the approach taken previously? If so, can > you describe any of the core ideas you feel are most important? > > Jordan > > External Links: > > [1]: https://externals.io/message/122735 > > [2]: https://externals.io/message/122994 > > [3]: https://externals.io/message/121387 > > [4]: https://externals.io/message/120822 > > [5]: https://externals.io/message/118971 > > I'm not experienced with other languages and overloading, so consider this reply as me not knowing enough about the subject. Rowan asked an interesting question: "Are we over-riding *operators* or *operations*?" which made me think about behaviors as a 3rd alternative. Instead of individual operator overloading, could classes define how they would act as certain primitives or types that have overloading under the hood? We have `Stringable` with `__toString`, which might not be the best example but does point in a similar direction. I don't know if this is a direction worth exploring but wanted to at least bring it up. ```php interface IntBehavior { public function asInt(): int; } class PositiveInt implements IntBehavior { public readonly int $value; public function __construct(int $value) { $this->value = max(0, $value); } public function asInt(): int { return $this->value; } } var_dump(10 + new PositiveInt(5)); // 15 var_dump(new PositiveInt(10) + 15); // 25 var_dump(new PositiveInt(100) + new PositiveInt(100)); // 200 // leaves it to the developer to do: $number = new PositiveInt(new PositiveInt(10) + 5); ```