The future of objects and operators

  117678
May 6, 2022 22:16 jordan.ledoux@gmail.com (Jordan LeDoux)
Hello all,

I took a while away after my operator overload RFC was declined. I've been
mulling for the last few months how to move forward while respecting the
concerns and feedback of those who abstained and those who voted against.
But I feel like a separate discussion needs to happen first after
considering many different approaches.

# There is Considerable Demand For Improved Control of Operators with
Objects

This doesn't apply to all operators. I have not seen any comments in the
last few months of digging of people who are desperate for the pow operator
( ** ) for instance. However, many people who work with math in PHP have
use for at least the arithmetic operators and I see this comment frequently.

Totally separate from the math domain, I've seen many comments about the
desire to control the comparison operators: >, >=, ==, <=, <, !=, <>. This
is something that would have numerous applications outside of mathematics,
and there's even been an RFC worked on (that was declined in 2018) by Rudi
to implement just comparisons.

# Different Voters Have Different Concerns

This is an issue that almost all RFC authors must deal with of course, but
this particular subject suffers from it more severely than most. For
instance, in some of the past proposals that were more limited than mine,
there were comments that a full operator overloading solution should be
provided instead of something halfway.

However one of the comments I received more than once was that I should
separate out the comparison operators into its own RFC, since those have
applications outside the math domain.

# Is Math A Valid Use Case?

One of the more shocking (to me personally) pieces of feedback that I
received from more than one person is that math is not a valid use case in
PHP. I am... unsure about what to think of this opinion. I guess I would
like to discuss and find out if this is widely believed among voters.

# Non-Breaking Engine Changes

The way that equality and comparison evaluation is done in the engine makes
it impossible for certain kinds of overloading to be done, even in
extensions. This isn't because that was an intended restriction, I
discussed this issue with CMB and provided a PR a few months ago to resolve
this, however it has remained in limbo:
https://github.com/php/php-src/pull/7973

# Overall Vision

I'm not sure at this point how voters think objects and operators should
work together into the future. I'd like to see if anyone is willing to have
high-level discussion about the ideas, instead of picking at the
implementation or details of a particular RFC.

Jordan
  117689
May 7, 2022 18:39 larry@garfieldtech.com ("Larry Garfield")
On Fri, May 6, 2022, at 5:16 PM, Jordan LeDoux wrote:
> Hello all, > > I took a while away after my operator overload RFC was declined. I've been > mulling for the last few months how to move forward while respecting the > concerns and feedback of those who abstained and those who voted against. > But I feel like a separate discussion needs to happen first after > considering many different approaches.
Speaking only for myself, of course...
> # There is Considerable Demand For Improved Control of Operators with > Objects > > This doesn't apply to all operators. I have not seen any comments in the > last few months of digging of people who are desperate for the pow operator > ( ** ) for instance. However, many people who work with math in PHP have > use for at least the arithmetic operators and I see this comment frequently. > > Totally separate from the math domain, I've seen many comments about the > desire to control the comparison operators: >, >=, ==, <=, <, !=, <>. This > is something that would have numerous applications outside of mathematics, > and there's even been an RFC worked on (that was declined in 2018) by Rudi > to implement just comparisons.
I would group object operators into 4 categories/levels. 1. Object-universal operators. This would be support for operators that make sense in all domains. Mainly this is the comparison operators but there may be others. 2. Arithmetic operators. The 4 basic operations. Maybe even just 3 (excluding division as it's a bit more complex than the others conceptually). 3. Full operator overloading: If an operator exists, a class can override it, on principle, even if there's no obvious common use case. 4. Custom overloading: User-space can define additional operators for specific objects. Jordan's RFC was effectively level 3, with a syntax designed to be extensible to level 4 in the future if desired. Naturally the line between these levels if a little bit fuzzy and there's some overlap.
> # Different Voters Have Different Concerns > > This is an issue that almost all RFC authors must deal with of course, but > this particular subject suffers from it more severely than most. For > instance, in some of the past proposals that were more limited than mine, > there were comments that a full operator overloading solution should be > provided instead of something halfway. > > However one of the comments I received more than once was that I should > separate out the comparison operators into its own RFC, since those have > applications outside the math domain.
See above regarding "levels" of support.
> # Is Math A Valid Use Case? > > One of the more shocking (to me personally) pieces of feedback that I > received from more than one person is that math is not a valid use case in > PHP. I am... unsure about what to think of this opinion. I guess I would > like to discuss and find out if this is widely believed among voters.
PHP is today rarely used for heavy-math use cases. It's mostly line-of-business applications, aka "over-engineered ways of concatenating strings out of a database." Historically it's been too slow for that, which lead to no community around it, so no one did it, so no focused improvements in that area, so... Infinite loop. Python got most of that attention instead. However, the JIT and FFI work have quite frankly very little use *other than* computation intensive (ie, math) use cases, and those were added without issue despite having APIs that are extremely crappy. :-) So I don't understand the "math doesn't matter" argument either; if it doesn't matter, we wouldn't have needed JIT or FFI either. I frankly think this is a red herring; it's a "I don't do heavy math work in PHP, so arguing that feature X makes PHP better for math carries no weight." It shouldn't be read as "PHP being good at complex computations is bad in itself." (If anyone does actually believe that, I'd say speak up but I'd just tell you that you're wrong from the get-go, so maybe let's not pick that fight and leave it as a hypothetical. :-) )
> # Non-Breaking Engine Changes > > The way that equality and comparison evaluation is done in the engine makes > it impossible for certain kinds of overloading to be done, even in > extensions. This isn't because that was an intended restriction, I > discussed this issue with CMB and provided a PR a few months ago to resolve > this, however it has remained in limbo: > https://github.com/php/php-src/pull/7973 > > # Overall Vision > > I'm not sure at this point how voters think objects and operators should > work together into the future. I'd like to see if anyone is willing to have > high-level discussion about the ideas, instead of picking at the > implementation or details of a particular RFC. > > Jordan
I am always down for high-level ideas discussions. :-P As even the detractors noted, the previous RFC is probably the best design that could be done, given PHP's existing nature. So aside from the `operator` syntax for semi-methods, I don't think there's much to discuss there. Conceptually, it is mostly true that any operator overload is simply syntactic sugar for a method call, and thus there's nothing that operator overloading enables that you can't do otherwise in more "self-documenting" ways (ie, methods). I think that was the main pushback, that overloading just adds less self-documenting syntactic sugar over stuff you can already do. However, there are 2 holes in that argument. One, the same is true of all operators on scalars, too. At a conceptual, computer-science-y level, all operators are shorthands for function calls. `5 + 3` is simply a shorthand for `add(int, int)` called with 5 and 3. (In some languages, scalar operators are literally implemented as functions/methods.) The only reason some common functions get magical short-hand operator syntax is historical precedent. A very common historical precedent, but still, there's nothing intrinsic in integer addition that makes it necessarily have a magic symbol shorthand for its function. In a pure sense, all operators are optional syntactic sugar. (Give or take language-specific optimization that could be designed any way you want it to.) Two, it's not entirely true that operator overloading offers no new functionality. PHP has a number of operations that rely on comparisons in particular that do not have any override mechanism. For example, `in_array()` with weak comparison can kinda-sorta work on arrays of objects, but only using the native "are each of the properties ==" algorithm. There is no way to override that to some other definition of equal, the way the usort() family of functions allows for custom user-space comparisons. in_array() offers no equivalent. So if you wanted to have a unique-list of objects (a set), you need to do an awful lot of manual work with custom object identity logic and avoiding all of PHP's built-in list handling features. It's technically possible to do, but at this point it's disingenuous to call it simply "syntactic sugar." What's missing is, effectively, an engine-hook for equality. That argument is less persuasive for the higher-level operators, like arithmetic or pow or modulus, as I am not aware of any missing "engine hook" situations for those. My recommendation would be to use the same syntax and model as before and just target object-universal operators, ie, comparisons. (Level 1 from above.) That gets the syntax in place, and lets us flush out the engine hook weirdness. If we could get that to pass, it would at least get people comfortable with the idea and concept. The higher level parts could then be an easier sell in the future in a version or two once people have gotten more used to the idea. On the topic of the specific syntax, the trade-offs of magic methods would be: * The names tell you what it is for, not what it looks like. This may or may not be a good thing. * It doesn't extend nicely to level 4 if we ever decide to go there. (Whether you consider this good or bad is subjective.) For the `operator` syntax, it's the other way around: * The name tells you what it looks like without restricting what you can use it for. This may or may not be a good thing. * Extending to later levels is syntactically trivial, including to level 4 if we want. (Again, whether that's a pro or a con is subjective.) I don't know if that particular syntax choice was a deal breaker for anyone but Nikita, though. --Larry Garfield
  117691
May 7, 2022 20:59 jordan.ledoux@gmail.com (Jordan LeDoux)
On Sat, May 7, 2022 at 11:40 AM Larry Garfield <larry@garfieldtech.com>
wrote:

> > I would group object operators into 4 categories/levels. > > 1. Object-universal operators. This would be support for operators that > make sense in all domains. Mainly this is the comparison operators but > there may be others. > 2. Arithmetic operators. The 4 basic operations. Maybe even just 3 > (excluding division as it's a bit more complex than the others > conceptually). > 3. Full operator overloading: If an operator exists, a class can override > it, on principle, even if there's no obvious common use case. > 4. Custom overloading: User-space can define additional operators for > specific objects. > > Jordan's RFC was effectively level 3, with a syntax designed to be > extensible to level 4 in the future if desired. Naturally the line between > these levels if a little bit fuzzy and there's some overlap. > ...
I frankly think this is a red herring; it's a "I don't do heavy math work
> in PHP, so arguing that feature X makes PHP better for math carries no > weight." It shouldn't be read as "PHP being good at complex computations > is bad in itself." (If anyone does actually believe that, I'd say speak up > but I'd just tell you that you're wrong from the get-go, so maybe let's not > pick that fight and leave it as a hypothetical. :-) ) > ... > My recommendation would be to use the same syntax and model as before and > just target object-universal operators, ie, comparisons. (Level 1 from > above.) That gets the syntax in place, and lets us flush out the engine > hook weirdness. If we could get that to pass, it would at least get people > comfortable with the idea and concept. The higher level parts could then > be an easier sell in the future in a version or two once people have gotten > more used to the idea. > > Of the people who did vote no and also provided me feedback, there were
*mainly* three reasons given (some in public such as on this list, and some in private in more direct conversation): 1. Math is not a valid use case. 2. Operator overloading for objects is something I will vote against in any context for any design, no matter the argument or evidence provided. 3. Operator overloading presents problems for static analysis and tooling which are more significant than the benefits. I could argue against all three positions, but as you noted, I don't think argument or debate is really helpful right now. Instead I'd like to talk at a more high level about what sort of long-term future PHP contributors and voters see for objects when it comes to allowing developers to control object behavior. I like the way you organized the different levels of support within the feature, it's a good organizational structure for thinking about the feature-set. Given the feedback though, I found myself a little concerned that if I created a Level 1 proposal, it's very possible that the people in groups 1 and 3 above might vote for it. However, in doing so it's also very possible that all the use-cases those voters care about would then be covered, and many would then block anything which helps use-cases they do not commonly use. In essence, the particular feedback I received made me concerned that passing a Level 1 RFC would basically guarantee that Level 2+ would never happen until the voter base itself was significantly changed. Even so... I think I agree with your suggestion at this point. At the very least, even if my concern above was proven true, it would then at least be *possible* for me to provide an extension for PHP which addresses some of the shortcomings for math. The main issue when it comes to comparisons is addressed in the PR I linked, which basically boils down to "for objects, it makes sense for equatable and comparable to be separated sometimes". Whether this involves a fall-through in the VM for objects as done in my linked PR, or involves new handlers for objects as CMB commented on that PR instead, it's actually a very minor change technically within the engine to implement Level 1 support as you described it. Jordan
  117697
May 8, 2022 11:36 a.leathley@gmx.net (Andreas Leathley)
On 07.05.22 22:59, Jordan LeDoux wrote:
> I like the way you organized the different levels of support within the > feature, it's a good organizational structure for thinking about the > feature-set. Given the feedback though, I found myself a little concerned > that if I created a Level 1 proposal, it's very possible that the people in > groups 1 and 3 above might vote for it. However, in doing so it's also very > possible that all the use-cases those voters care about would then be > covered, and many would then block anything which helps use-cases they do > not commonly use. In essence, the particular feedback I received made me > concerned that passing a Level 1 RFC would basically guarantee that Level > 2+ would never happen until the voter base itself was significantly changed. Creating "smaller steps" (within a certain feature set) seems to have
been the more successful route for PHP RFCs and not necessarily slowed down further enhancements, in my estimation. The more one single RFC is about, the more there is to possibly dislike. It is also easier to reason about less changes at any one point in time and make a more compelling case for the changes. So I think your overall goal of more feature-complete operator overloading remains viable even if you start "small" with a level 1 proposal.
  117706
May 9, 2022 21:25 larry@garfieldtech.com ("Larry Garfield")
On Sat, May 7, 2022, at 3:59 PM, Jordan LeDoux wrote:

> Of the people who did vote no and also provided me feedback, there were > *mainly* three reasons given (some in public such as on this list, and some > in private in more direct conversation): > > 1. Math is not a valid use case. > 2. Operator overloading for objects is something I will vote against in any > context for any design, no matter the argument or evidence provided. > 3. Operator overloading presents problems for static analysis and tooling > which are more significant than the benefits. > > I could argue against all three positions, but as you noted, I don't think > argument or debate is really helpful right now. Instead I'd like to talk at > a more high level about what sort of long-term future PHP contributors and > voters see for objects when it comes to allowing developers to control > object behavior. > > I like the way you organized the different levels of support within the > feature, it's a good organizational structure for thinking about the > feature-set. Given the feedback though, I found myself a little concerned > that if I created a Level 1 proposal, it's very possible that the people in > groups 1 and 3 above might vote for it. However, in doing so it's also very > possible that all the use-cases those voters care about would then be > covered, and many would then block anything which helps use-cases they do > not commonly use. In essence, the particular feedback I received made me > concerned that passing a Level 1 RFC would basically guarantee that Level > 2+ would never happen until the voter base itself was significantly changed.
It's possible. However, it wouldn't be the first feature that has laid dormant for several years until the voting population turned over. (Scalar types and attributes are the first such examples that come to mind, but I'm sure there's others.) Also, not proposing level 1 on the grounds that it would reduce the argument for level 2/3 in the future would effectively be holding level 1 functionality "hostage" for the more advanced versions, which... would probably not work out well. :-) (Even if that's not your intent, it would come off that way.) Conversely, giving people a version or three to work with level 1 operator overloads may get more people comfortable with the concept and thus make them more amenable to levels 2 or 3 in the future. Whether there's enough support for level 1 for it to pass at the moment, I honestly don't know.
> Even so... I think I agree with your suggestion at this point. At the very > least, even if my concern above was proven true, it would then at least be > *possible* for me to provide an extension for PHP which addresses some of > the shortcomings for math. > > The main issue when it comes to comparisons is addressed in the PR I > linked, which basically boils down to "for objects, it makes sense for > equatable and comparable to be separated sometimes". Whether this involves > a fall-through in the VM for objects as done in my linked PR, or involves > new handlers for objects as CMB commented on that PR instead, it's actually > a very minor change technically within the engine to implement Level 1 > support as you described it. > > Jordan
I defer to you and others on the technical implementation, as it's well outside my wheelhouse. --Larry Garfield
  117721
May 12, 2022 17:42 jordan.ledoux@gmail.com (Jordan LeDoux)
On Mon, May 9, 2022 at 2:25 PM Larry Garfield <larry@garfieldtech.com>
wrote:

> > Also, not proposing level 1 on the grounds that it would reduce the > argument for level 2/3 in the future would effectively be holding level 1 > functionality "hostage" for the more advanced versions, which... would > probably not work out well. :-) (Even if that's not your intent, it would > come off that way.) > > > Yes, I also realize that, which is another reason I'm thinking that doing
comparison-only overloads first might be the better way forward.
  117694
May 7, 2022 22:08 mike@newclarity.net (MKS Archive)
> On May 6, 2022, at 6:16 PM, Jordan LeDoux ledoux@gmail.com> wrote: > > Hello all, > > I took a while away after my operator overload RFC was declined. I've been > mulling for the last few months how to move forward while respecting the > concerns and feedback of those who abstained and those who voted against. > But I feel like a separate discussion needs to happen first after > considering many different approaches. > > # There is Considerable Demand For Improved Control of Operators with > Objects > > This doesn't apply to all operators. I have not seen any comments in the > last few months of digging of people who are desperate for the pow operator > ( ** ) for instance. However, many people who work with math in PHP have > use for at least the arithmetic operators and I see this comment frequently. > > Totally separate from the math domain, I've seen many comments about the > desire to control the comparison operators: >, >=, ==, <=, <, !=, <>. This > is something that would have numerous applications outside of mathematics, > and there's even been an RFC worked on (that was declined in 2018) by Rudi > to implement just comparisons. > > # Different Voters Have Different Concerns > > This is an issue that almost all RFC authors must deal with of course, but > this particular subject suffers from it more severely than most. For > instance, in some of the past proposals that were more limited than mine, > there were comments that a full operator overloading solution should be > provided instead of something halfway. > > However one of the comments I received more than once was that I should > separate out the comparison operators into its own RFC, since those have > applications outside the math domain. > > # Is Math A Valid Use Case? > > One of the more shocking (to me personally) pieces of feedback that I > received from more than one person is that math is not a valid use case in > PHP. I am... unsure about what to think of this opinion. I guess I would > like to discuss and find out if this is widely believed among voters.
I will repeat what I suggested back before the RFC was voted on, and that is you consider *starting* your campaign for operator overloads with an RFC to add a built-in Math class (or set of classes) to PHP, one(s) that can have all the operator overloading it/they need(s). Minimally the design process in the open would be insightful for everyone interested in the topic even if the RFC did not get accepted — although the intent should be that it would — because it would change the operator overload discussion from a very abstract one to a very concrete one. It could also illustrate the benefit for operator overloading, and illustrate the design process of deciding on how operators are overloaded and what the benefits and tradeoffs are of different choices. If the RFC did not pass, at least it could result in an understanding of which operators minimally need to be overloaded for the Math use-case and serve as a blueprint for adding Math objects in userland if and when sufficient general-purpose operator overloading could get added to PHP. Further, if an RFC to add a built-in Math object to PHP passed it would effectively eliminate the red-herring of "I don't do heavy math work." Such an RFC would also, of course, not have the other two (2) categories of objections that you named in your other email. Again, #jmtcw -Mike
  117711
May 10, 2022 17:31 tor.edvardsson@outlook.com (Tor Edvardsson)
Hi

> # Overall Vision
Even though I'm just a PHP pleb I thought I give you my opinion on the matter. If the following arguments is nothing but a repetition of what is argued in the RFC or in previous discussions I apologize. # Introduction Historically I have been against operator overloading, however since Jordan posted his first RFC on the subject I started to reevaluate my position. What I realized is that I had just accepted the argument that operator overloading creates unnecessary complexity, why? Because C++ has operator overloading and we all know that C++ is a very complex language and therefore it is an bad idea, however that argument is somewhat of fallacy. Reevaluating operator overloading I came to the conclusion that many of the issues that has been discussed within the PHP community can be solved with operator overloading. What operator overloading enables us to do is to let the community to evolve the language without the formalities of the RFC process, it is a true decentralized governance, which is a good fit for a community based language like PHP. Lets go over some of the recurring issues that has been discussed within the PHP community over the years. I assume here is what Larry specifies as object operators level 3 and optionally 4. I try to keep this as an high-level discussion to avoid any technical arguments regarding the PHP engine because that is outside of my expertise. # Object primitives (scalar objects) One recurring criticism against PHP is that it doesn't have methods attached to primitive types like other dynamic languages has, e.g. strpos($haystack, $needle) instead of $haystack->strpos($needle) Nikic implemented a branch where he tested this https://github.com/nikic/scalar_objects With operator overloading we can implement this in user land and still use our object primitives together with normal primitives. And it would also be possible to inherit these object primitives for custom object primitives, like an int range. # Strict comparison Another issue is that every comparison, except for strict equal, is a loose comparison with implicit type casting. If I remember correctly someone suggested that we could add another declare directive, similar to strict_types, to enable strict comparison per php file. With operator overloading there is no need to add another directive. Assume the following (new Integer(3)) * 3 < $x if the multiplication returns an Integer instance that is then used in the following comparison step, Integer can enforce strict typing and throw a TypeError on mismatch. # Tainted input Another issue is to handle tainted input, e.g. from query parameters, to avoid injection attacks when doing SQL queries. What I can see is that this is something that has been discussed for quite a long time. Currently there is no way for user land code to detect where a string originated from. With operator overloading a framework could at least within the confines of the framework start to somewhat handle this issue. Assume we have following two classes class SafeString { // ... } class UnsafeString { // ... } Both implement the string append operator (.), on append both return the same type of instance as them selves except that appending with UnsafeString must always return UnsafeString. string literals could be assumed to be SafeString. Now the framework could have these two functions function queryParam(string $name): UnsafeString; function executeSqlQuery(SafeString $query, array $params): int; The GET queryParam() returns an UnsafeString that is incompatible with the $query argument for executeSqlQuery(). A programmer can still of course escape out to the standard library and avoid this, but it gives a least frameworks some tools to avoid the most common mistakes. # Escaped output Assume we could add a custom operator that is the echo operator (note this is not the same as _toString()). When doing PHP templating with we could then automatically escape string objects. # A new standard library What all of these gives us is actually a new standard library driven by the community. It is an recurring theme to complain on the standard library, parameter order, function naming, lack of namespaces, not OOP etc. You all have heard it. But with operator overloading we give the community a chance to build something better without breaking the current one. And perhaps over the years the community has produced something good that could be merged into PHP. Currently I think the standard library is one of the biggest weaknesses of PHP, it is not bad, it is actually quite good, but the packaging has a big negative effect, especially on newcomers. There is almost no benefit of cleaning up the current standard library by renaming functions and reordering parameters, that would only create havoc with minimal benefits, but unfortunately that also stops us from actually getting a better designed standard library. Operator overloading could be a way out of this dilemma, where we can implement a new powerful standard library without breaking the past and at the same time offer more expressiveness. # Conclusion These are just a few things I have been thinking of the past months, I have not properly tested the feasibility of them, thus there may be some flaws in them, but you are free to comment on it. Thanks. Tor
  117727
May 13, 2022 14:05 rowan.collins@gmail.com (Rowan Tommins)
On 6 May 2022 23:16:37 BST, Jordan LeDoux ledoux@gmail.com> wrote:
>I'm not sure at this point how voters think objects and operators should >work together into the future. I'd like to see if anyone is willing to have >high-level discussion about the ideas, instead of picking at the >implementation or details of a particular RFC.
Hi Jordan, I like Larry's "4 levels", but I've been thinking that there's some existing functionality in PHP which takes a different direction: rather than overloading *operators*, the language lets you overload *behaviour*. We have magic methods like __get and __call, and interfaces like Iterator, Countable, and ArrayAccess. Some hook into a particular function, or even operator, but they're generally described in terms of what they do, not what they look like, if you see what I mean. From that point of view, overloading comparison and equality *behaviour* makes sense - it could affect not just the == and <=> operators, but things like in_array() and sort(). I think this distinction is more pronounced in PHP than some languages, because the standard library isn't "self-hosted": a sort() call doesn't literally compile to a call to $a <=> $b It's less obvious how that applies to mathematical operators - should implementing "addition" allow an object to be used with array_sum() perhaps? And what about deriving one operation from another, e.g. $foo*3 running $foo+$foo+$foo, or $foo**3 running $foo*$foo*$foo? I don't really have a conclusion here, I just wanted to throw it out there as a different mental model to consider. Regards, -- Rowan Tommins [IMSoP]
  117728
May 13, 2022 14:26 larry@garfieldtech.com ("Larry Garfield")
On Fri, May 13, 2022, at 9:05 AM, Rowan Tommins wrote:
> On 6 May 2022 23:16:37 BST, Jordan LeDoux ledoux@gmail.com> wrote: >>I'm not sure at this point how voters think objects and operators should >>work together into the future. I'd like to see if anyone is willing to have >>high-level discussion about the ideas, instead of picking at the >>implementation or details of a particular RFC. > > > Hi Jordan, > > I like Larry's "4 levels", but I've been thinking that there's some > existing functionality in PHP which takes a different direction: rather > than overloading *operators*, the language lets you overload > *behaviour*. We have magic methods like __get and __call, and > interfaces like Iterator, Countable, and ArrayAccess. Some hook into a > particular function, or even operator, but they're generally described > in terms of what they do, not what they look like, if you see what I > mean. > > From that point of view, overloading comparison and equality > *behaviour* makes sense - it could affect not just the == and <=> > operators, but things like in_array() and sort(). I think this > distinction is more pronounced in PHP than some languages, because the > standard library isn't "self-hosted": a sort() call doesn't literally > compile to a call to $a <=> $b > > It's less obvious how that applies to mathematical operators - should > implementing "addition" allow an object to be used with array_sum() > perhaps? And what about deriving one operation from another, e.g. > $foo*3 running $foo+$foo+$foo, or $foo**3 running $foo*$foo*$foo? > > I don't really have a conclusion here, I just wanted to throw it out > there as a different mental model to consider.
Interesting point. I think that's the most compelling argument I've heard for using `public function __lessThan` rather than `operator <`. I'm not sure if it's enough to change my own preference on that front, but it's an interesting point. Working with `in_array()` and `sort()` is a necessary feature for comparison overloading, IMO. I'm unsure about something like `array_sum()`, but could be convinced. Hum. --Larry Garfield
  117729
May 13, 2022 14:49 jordan.ledoux@gmail.com (Jordan LeDoux)
On Fri, May 13, 2022 at 7:05 AM Rowan Tommins collins@gmail.com>
wrote:

> > I like Larry's "4 levels", but I've been thinking that there's some > existing functionality in PHP which takes a different direction: rather > than overloading *operators*, the language lets you overload *behaviour*. > We have magic methods like __get and __call, and interfaces like Iterator, > Countable, and ArrayAccess. Some hook into a particular function, or even > operator, but they're generally described in terms of what they do, not > what they look like, if you see what I mean. > > From that point of view, overloading comparison and equality *behaviour* > makes sense - it could affect not just the == and <=> operators, but things > like in_array() and sort(). I think this distinction is more pronounced in > PHP than some languages, because the standard library isn't "self-hosted": > a sort() call doesn't literally compile to a call to $a <=> $b > > I have been thinking about something similar, but not in the context of
making operator overloads more like behavior overloads. Rather, I've been considering the idea that operator overloads are a *subset* of *engine overloads*. Ways that the developer can provide additional details to the engine about the behavior of their code that allows the engine to make more concrete assumptions about how it should be processed and interpreted. I started thinking about this mainly from the perspective of the syntax. I proposed the `operator +()` syntax in my overloads RFC, but my most compelling argument about the reason for it was sort of obscured because it was wrapped up in only overloads. To that end, I was considering more broadly what *all* magic methods are on objects: handlers. In fact, in the Zend engine that's how many of the same sorts of behaviors are described, as object handlers. Most of the standard library functions don't make calls for such handlers. For instance, sort() makes a call to zend_compare, and zend_compare ends up making a call to the compare handler on the relevant object. So I was at least considering the idea of a more broad replacement of the syntax for object behaviors, just not for an RFC related to overloads... such an RFC would have its own difficulties and controversy, and would almost certainly require a period of dual syntax support for old magic method syntax, making the arguments against very easy while the benefits would be more long term and less immediately apparent.
> It's less obvious how that applies to mathematical operators - should > implementing "addition" allow an object to be used with array_sum() > perhaps? And what about deriving one operation from another, e.g. $foo*3 > running $foo+$foo+$foo, or $foo**3 running $foo*$foo*$foo? > > I don't really have a conclusion here, I just wanted to throw it out there > as a different mental model to consider. > > This would only be true for numerics, but not other kinds of math, such as
matrices. Mathematical operators really are something that require direct calls and direct overloads if they are supported in any way, unless the language is willing to essentially never have things like complex numbers, matrices, etc. even in extensions. Still, it's an interesting thought and definitely the kind of high-level discussion I was looking for. Jordan
  117943
June 14, 2022 13:57 landers.robert@gmail.com (Robert Landers)
On Fri, May 13, 2022 at 4:49 PM Jordan LeDoux ledoux@gmail.com> wrote:
> > On Fri, May 13, 2022 at 7:05 AM Rowan Tommins collins@gmail.com> > wrote: > > > > > I like Larry's "4 levels", but I've been thinking that there's some > > existing functionality in PHP which takes a different direction: rather > > than overloading *operators*, the language lets you overload *behaviour*. > > We have magic methods like __get and __call, and interfaces like Iterator, > > Countable, and ArrayAccess. Some hook into a particular function, or even > > operator, but they're generally described in terms of what they do, not > > what they look like, if you see what I mean. > > > > From that point of view, overloading comparison and equality *behaviour* > > makes sense - it could affect not just the == and <=> operators, but things > > like in_array() and sort(). I think this distinction is more pronounced in > > PHP than some languages, because the standard library isn't "self-hosted": > > a sort() call doesn't literally compile to a call to $a <=> $b > > > > > I have been thinking about something similar, but not in the context of > making operator overloads more like behavior overloads. Rather, I've been > considering the idea that operator overloads are a *subset* of *engine > overloads*. Ways that the developer can provide additional details to the > engine about the behavior of their code that allows the engine to make more > concrete assumptions about how it should be processed and interpreted. > > I started thinking about this mainly from the perspective of the syntax. I > proposed the `operator +()` syntax in my overloads RFC, but my most > compelling argument about the reason for it was sort of obscured because it > was wrapped up in only overloads. To that end, I was considering more > broadly what *all* magic methods are on objects: handlers. In fact, in the > Zend engine that's how many of the same sorts of behaviors are described, > as object handlers. > > Most of the standard library functions don't make calls for such handlers. > For instance, sort() makes a call to zend_compare, and zend_compare ends up > making a call to the compare handler on the relevant object. So I was at > least considering the idea of a more broad replacement of the syntax for > object behaviors, just not for an RFC related to overloads... such an RFC > would have its own difficulties and controversy, and would almost certainly > require a period of dual syntax support for old magic method syntax, making > the arguments against very easy while the benefits would be more long term > and less immediately apparent. > > > > It's less obvious how that applies to mathematical operators - should > > implementing "addition" allow an object to be used with array_sum() > > perhaps? And what about deriving one operation from another, e.g. $foo*3 > > running $foo+$foo+$foo, or $foo**3 running $foo*$foo*$foo? > > > > I don't really have a conclusion here, I just wanted to throw it out there > > as a different mental model to consider. > > > > > This would only be true for numerics, but not other kinds of math, such as > matrices. Mathematical operators really are something that require direct > calls and direct overloads if they are supported in any way, unless the > language is willing to essentially never have things like complex numbers, > matrices, etc. even in extensions. > > Still, it's an interesting thought and definitely the kind of high-level > discussion I was looking for. > > Jordan
Sorry to resurrect an old conversation, but today I'm doing some complex/big-number math (with a compatibility layer around GMP) in PHP, and it made me realize how much I'd appreciate at least some operator support in PHP. Current code: function modNear(BN $a, BN $b): BN { $res = $a->mod($b); if($res->gt($b->shrn(1))) { return $res->sub($b); } return $res; } Desired code: function modNear(BN $a, BN $b): BN { $res = $a % $b; if($res > ($b >> 1)) { return $res - $b; } return $res; } The latter is much easier to grok at a glance.