jan.h.boeh...@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



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to