# [RFC] Userspace operator overloading

- Thread: https://externals.io/message/108608
- Original archive: https://news-web.php.net/php.internals/108608
- Started by jan.h.boehmer@gmx.de on 2020-02-15T22:05:52+00:00
- Messages: 7
- RFC: Userspace Operator overloading (Declined) — https://externals.io/rfc/userspace_operator_overloading.md
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · RFCs at https://externals.io/rfc.md · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #108608 — jan.h.boehmer@gmx.de — 2020-02-15T22:05:52+00:00

URL: https://externals.io/message/108608#108608

Hi internals,

based on the discussions here (https://externals.io/message/108300) and here
(https://github.com/php/php-src/pull/5156), I have created a proper RFC for
userspace operator overloading:
https://wiki.php.net/rfc/userspace_operator_overloading

The main differences to my original concept, is the removed __compare()
method (comparison overloading is a complex topic and should be handled in a
different RFC) and the possibility to signal that the operator handler does
not support the given types (by typehints or returning a special value).
This way, only one of both objects has to know about the other type. This
should expand the use case of operator overloading compared to my old
concept.

What do you think about the RFC?

Some discussion points, I can think of, would be the naming of the methods
(maybe naming them after the operator symbol and not the arithmetical
operation they represent, e.g. __plus instead of __add) or putting the
methods inside of interfaces like done for ArrayAccess (But I dont see any
advantage in doing so, as it is very difficult grouping different operators
in a single interface usefully. Also, operators can accept and return
different types, so there is no real common interface between classes you
could rely on).
Furthermore, maybe the idea of allowing operator overloading in general
should be discussed as it is sometimes considered an anti-pattern (e.g. the
usage of '<<' for outputting a string in C++). On the other hand there are
many languages and libraries where operator overloading is used successfully
(e.g. numpy in Python).

Regards,
Jan Böhmer

---

## #108612 — Mark Randall — 2020-02-16T01:17:25+00:00

URL: https://externals.io/message/108608#108612 · In reply to: #108608

> Hi internals,
> What do you think about the RFC?

"If an operator is used with an object that does not overload this 
operator, an NOTICE is triggered, which gives the user a hint about the 
method that has to be overloaded. For backward compatibility objects, 
which do not overload the operator, are converted to integer 1 (current 
behavior)."

Noooo :( Notices are the enemy of all that is great and good.

If operator overloading is going to become a first-class feature then it 
should be treated as such, and attempting overloading operators on 
objects that don't have the relevant method available should trigger an 
Error.

--
Mark Randall
marandall@php.net

---

## #108614 — Rowan Tommins — 2020-02-16T01:54:21+00:00

URL: https://externals.io/message/108608#108614 · In reply to: #108608

>Some discussion points, I can think of, would be the naming of the
>methods
>(maybe naming them after the operator symbol and not the arithmetical
>operation they represent, e.g. __plus instead of __add) or putting the
>methods inside of interfaces like done for ArrayAccess


As I mentioned earlier [1] I think the answers to both of these questions depend on a fundamental philosophical question about what you're overloading:

- The groups of operations which exist for built-in types e.g. the arithmetic operations overloaded by GMP; or string operations overloaded by an object with enhanced Unicode functionality.

- The individual symbolic operators, with no intrinsic meaning - e.g. overloading . for concatenation on strings but dot-product for vectors; or a DSL overloading << and >> for "into" and "out of".

I think it would benefit the RFC to take a stance on that question, and build the feature around it.


[1] https://news-web.php.net/php.internals/108347

-- 
Rowan Tommins
[IMSoP]

---

## #108615 — Stanislav Malyshev — 2020-02-16T05:07:03+00:00

URL: https://externals.io/message/108608#108615 · In reply to: #108614

Hi!

> - The individual symbolic operators, with no intrinsic meaning - e.g.
> overloading . for concatenation on strings but dot-product for
> vectors; or a DSL overloading << and >> for "into" and "out of".

Please no. I know it looks fancy and some languages love it, but for a
person not in on the joke reading such code is a nightmare - it's
basically gibberish until you learn all the types and which meaning each
of the types assigns to operators. I mean, I could be maybe talked into
having users overload "+" to mean "add some kind of objects that are
like numbers but not actually integers" because my intuition still works
there even if I don't know the exact type. But if someone thinks it's
super-cool to override + to make it add element to the cache object -
please no. It's way worse than just using plain old ->addObject(). You
may save couple of keystrokes and make your code completely
incomprehensible for people who come after you.

I know DSLs have its niche but I seriously doubt average PHP user
implements a lot of DSLs that are required to work natively on PHP engine.
-- 
Stas Malyshev
smalyshev@gmail.com

---

## #108617 — Rowan Tommins — 2020-02-16T10:31:14+00:00

URL: https://externals.io/message/108608#108617 · In reply to: #108615

>Hi!
>
> > […]
>
>Please no. I know it looks fancy and some languages love it, but for a
>person not in on the joke reading such code is a nightmare

:) I know you're not alone in that feeling. If it turns out this is the majority view, I think it answers a couple of open questions:

Overload methods should definitely be named after operations, not symbols, to remind people they are implementing addition, not giving new meaning to +

They should probably be grouped into interfaces, which this RFC has so far resisted. How often does it make sense for a type to support addition but not subtraction, or multiplication but not division? Even more clearly, if a type claims to implement bitwise OR but not bitwise AND, NOT, and XOR, something is definitely fishy.

You can't stop people using overloading DSL-style, but you can make it obvious that it's not the intention of the feature (if we agree that it's not the intention; maybe some people here are really hoping to use it that way?)

Regards,

-- 
Rowan Tommins
[IMSoP]

---

## #108619 — G. P. B. — 2020-02-16T12:28:10+00:00

URL: https://externals.io/message/108608#108619 · In reply to: #108608

> Hi internals,
>
> based on the discussions here (https://externals.io/message/108300) and
> here
> (https://github.com/php/php-src/pull/5156), I have created a proper RFC
> for
> userspace operator overloading:
> https://wiki.php.net/rfc/userspace_operator_overloading
>
> The main differences to my original concept, is the removed __compare()
> method (comparison overloading is a complex topic and should be handled in
> a
> different RFC) and the possibility to signal that the operator handler does
> not support the given types (by typehints or returning a special value).
> This way, only one of both objects has to know about the other type. This
> should expand the use case of operator overloading compared to my old
> concept.
>
> What do you think about the RFC?
>
> Some discussion points, I can think of, would be the naming of the methods
> (maybe naming them after the operator symbol and not the arithmetical
> operation they represent, e.g. __plus instead of __add) or putting the
> methods inside of interfaces like done for ArrayAccess (But I don’t see any
> advantage in doing so, as it is very difficult grouping different operators
> in a single interface usefully. Also, operators can accept and return
> different types, so there is no real common interface between classes you
> could rely on).
> Furthermore, maybe the idea of allowing operator overloading in general
> should be discussed as it is sometimes considered an anti-pattern (e.g. the
> usage of '<<' for outputting a string in C++). On the other hand there are
> many languages and libraries where operator overloading is used
> successfully
> (e.g. numpy in Python).
>
> Regards,
> Jan Böhmer
>
> --
> 
> 
>
>
Just as a FYI, I'll vote No to this RFC regardless of arguments as I find
operator
(and method) overloading a bad idea in general. Moreover, the only ones I am
a tiny bit less reluctant to overload are the mathematical operators.

However, one of the major reasons to want to have this seems to add better
support for Matrices and Complex number which can already be done at the
extension/engine level.

Best regards

George P. Banyard

---

## #108722 — terje.slettebo@sandefjordbredband.net — 2020-02-22T16:04:15+00:00

URL: https://externals.io/message/108608#108722 · In reply to: #108608

jan.h.boehmer@gmx.de wrote:

> based on the discussions here (https://externals.io/message/108300)
> and here (https://github.com/php/php-src/pull/5156), I have created a
> proper RFC for userspace operator overloading:
> https://wiki.php.net/rfc/userspace_operator_overloading
> 
> The main differences to my original concept, is the removed
> __compare() method (comparison overloading is a complex topic and
> should be handled in a different RFC) and the possibility to signal
> that the operator handler does not support the given types (by
> typehints or returning a special value). This way, only one of both
> objects has to know about the other type. This should expand the use
> case of operator overloading compared to my old concept.
> 
> What do you think about the RFC?

I very much appreciate this initiative, as well as that of Patricio/Sara, 
and I agree with what people have said about the importance of realistic 
use-cases for something like this.

Our company produces ads, and the price calculation is quite complex, involving 
the size of the ads, various discounts, etc. We're using objects for these 
calculations, to ensure we don't mix up units.

Here are some examples:

$price_per_column_mm = new PricePerColumnMm(1234); // Price = 1234 * number 
of columns * height in mm

$height = new LengthInMm(100);

$price_per_column = $price_per_column_mm->multiply($height); // Returns a 
PricePerColumn object

$columns = new Column(4);

$price = $price_per_column->multiply($columns); // Returns a Money object

It gets more complicated, when we add in discounts:

$discount_percentage = new Percentage(10);

$end_user_price = $price->subtract($discount_percentage); // Price = Price 
* (100-discount percentage)/100

These are just a few examples, but it shows the advantage of using strongly 
typed objects in expressions, so that we don't do nonsensical things like 
multiplying two Money objects, or try to use a PricePerColumn object as a 
Money object.

As you can probably tell, having all those "add", "subtract", "multiply", 
etc. method calls makes it hard to understand what is going on, and even 
if things happen in the right order, because when you use method calls, you 
can't change the order of execution without breaking an expression up into 
multiple expressions: It always happens from left to right.

In order to support code like the above, we'd need to be able to define the 
following operators:

PricePerColumnMm * LengthInMm -> PricePerColumn

PricePerColumn * Column -> Money

Money - Percentage -> Money

This comes in addition to the usual operators that takes the same type on 
both sides, such as Money + Money, etc.

Please note the last one, which is a non-commutative operation (Money - Percentage 
!= Percentage - Money), which wouldn't work in Patricio's proposal, unless 
the "Associativity" section is rewritten to handle this in a different way.

I like Patricio's proposal in that it uses ordinary, non-static methods, 
but unfortunately, it then runs into this problem, which seems to favour 
Jan's proposal.

With regard to the mechanism for handling this (interfaces, magic methods, 
or a magic __overload() method), or Sara's proposal for registering overloads, 
using overload_type(), none of that are deal-breakers for me.

Still, as we already have "magic methods" for other things (and interfaces, 
yes, I know), I'd lean towards implementing these as magic methods, which 
lets a developer only implement the operations that makes sense in their 
domain.

Also, I think we should distinguish between non-assign and assign operators, 
giving them different method names, because some types may be expensive to 
copy, for example a large matrix, so $matrix *= $vector could be way more 
efficient than $matrix = $matrix * $vector.

Regards,

Terje
