Would there be an RFC to push this feature(with the right handler, POC)
into PHP?

Or something would stop it from happening?



On Wed, 29 Jan 2020, 10:20 am Nikita Popov, <nikita....@gmail.com> wrote:

> On Wed, Jan 29, 2020 at 12:14 AM <jan.h.boeh...@gmx.de> wrote:
>
> > Hello everybody,
> >
> >
> >
> > the last days I have experimented a bit with operator overloading in
> > userspace classes (redefing the meaning of arithmetic operations like +,
> -,
> > *, etc. for your own classes).
> >
> > This could be useful for different libraries which implements custom
> > arithmetic objects (like money values, tensors, etc.) or things like
> > Symfony
> > string component (concatenate) operator, because it improves readability
> > much:
> >
> > $x * ($a + $b) instead of $x->multiply($a->add($b))
> >
> >
> >
> > 4 years ago, there was a RFC about this topic (
> > <https://wiki.php.net/rfc/operator-overloading>
> > https://wiki.php.net/rfc/operator-overloading), which was discussed a
> bit
> > (
> > <https://externals.io/message/89967> https://externals.io/message/89967
> ),
> > but there was no real Outcome.
> >
> >
> >
> > I have tried to implement a proof of concept of the RFC, I encountered
> some
> > problems, when implementing the operator functions as (non-static) class
> > members and pass them only the “other” argument: What happens when we
> > encounter an expression like 2/$a and how can the class differ this from
> > $a/2. Also not every operation on every structure is e.g on commutative
> > (e.g. for matrices A*B =/= B*A). So I tried a C#-like approach, where the
> > operator implementations are static functions in the class, and both
> > arguments are passed. In my PHP implementation this would look something
> > like this:
> >
> >
> >
> > Class X {
> >
> >     public static function __add($lhs, $rhs) {
> >
> >                 //...
> >
> >    }
> >
> > }
> >
> >
> >
> > The class function can so decide what to do, based on both operands (so
> it
> > can decide if the developer wrote 2/$a or $a/2). Also that way an
> > implementor can not return $this by accident, which could lead to
> > unintended
> > side effect, if the result of the operation is somehow mutated.
> >
>
> Using static methods sounds reasonable to me.
>
> I have taken over the idea of defining a magic function for each operation
> > (like Python does), because I think that way it is the clearest way to
> see,
> > what operators a class implements (could be useful for static analysis).
> > The
> > downside to this approach is that this increases the number of magic
> > functions highly (my PoC-code defines 13 additional magic functions, and
> > the
> > unary operators are missing yet), so some people in the original
> discussion
> > suggest to define a single (magic) function, where the operator is
> passed,
> > and the user code decides, what to do. Advantageous is very extensible
> > (with
> > the right parser implementation, you could even define your own new
> > operators), with the cost that this method will become very complex for
> > data
> > structures which use multiple operators (large if-else or switch
> > constructions, which delegate the logic to the appropriate functions). An
> > other idea mentioned was to extract interfaces with common functionality
> > (like Arithmetically, Comparable, etc.) like done with the ArrayAccess or
> > Countable interfaces. The problem that I see here, is that this approach
> is
> > rather unflexible and it would be difficult to extract really universal
> > interfaces (e.g. vectors does not need a division (/) operation, but the
> > concatenation . could be really useful for implementing dot product).
> This
> > would lead to either that only parts of the interfaces are implemented
> (and
> > the other just throw exceptions) or that the interfaces contain only one
> or
> > two functions (so we would have many interfaces instead of magic
> functions
> > in the end).
> >
>
> Yes, i don't think it makes sense to group these operations in interfaces,
> the use-cases are just too diverse. It's possible to define one interface
> per operator (e.g. what Rust does), though I don't think this is going to
> be particularly useful in PHP. I would not want to see functions accepting
> int|float|(Add&Mul) show up, because someone is trying to be overly generic
> in their interfaces ;)
>
> As to whether it should be a single method or multiple, I would go for
> multiple methods, as that makes it more clear which operators are
> overloaded from an API perspective.
>
> On the topic which operators should be overloadable: My PoC-implementation
> > has magic functions for the arithmetic operators (+, -, *, /, %, **),
> > string
> > concatenation (.), and bit operations (>>, <<, &, |, ^). Comparison and
> > equality checks are implement using a common __compare() function, which
> > acts like an overload of the spaceship operator. Based if -1, 0 or +1 is
> > returned by the  comparison operators (<, >, <=, >=, ==) are evaluated. I
> > think this way we can enforce, that the assumed standard logic (e.g
> > !($a<$b)=($a>=$b) and ($a<$b)=($b>$a)) of comparison is implemented.
> Also I
> > don’t think this would restrict real world applications much (if you have
> > an
> > example, where a separate definition of < and >= could be useful, please
> > comment it).
> >
>
> I would recommend not handling overloading of comparisons in the same
> proposal. Comparison is more widely useful than other overloading and has a
> more complex design space (especially when it comes to accommodating
> objects that can only be compared for equality/inequality for example).
> Comparison may also benefit more from having an interface than the other
> operators.
>
>
> > Unlike the original idea, I don’t think it should be possible to
> overwrite
> > identity operator (===), because it should always be possible to check if
> > two objects are really identical (also every case should be coverable by
> > equality). The same applies to the logic operators (!, ||, &&), I think
> > they
> > should always work like intended (other languages like Python and C#
> > handles
> > it that way too).
> >
>
> I agree that === should not be overloadable. || and && are
> short-circuiting, so overloading them in any meaningful way would be pretty
> hard anyway (we'd have to implicitly wrap the RHS into a closure or ...
> something?)
>
>
> > For the shorthand assignment operators like +=, -= the situation is a bit
> > more complicated: On the one hand the user has learned that $a+=1 is just
> > an
> > abbreviation of $=$a+1, so this logic should apply to overloaded
> operators
> > as well (in C# it is implemented like this). On the other hand it could
> be
> > useful to differentiate between the two cases, so you can mutate the
> object
> > itself (in the += case) instead of returning a new object instance (the
> > class cannot know it is assigned to its own reference, when $a + 1 is
> > called). Personally I don’t think that this would be a big problem, so my
> > PoC-Code does not provide a possibility to override the short hand
> > operators.) For the increment/decrement operators ($a++) it is similar,
> it
> > would be nice if it would be possible to overload this operator but on
> the
> > other hand the use cases of this operator is really limited besides
> integer
> > incrementation and if you want to trigger something more complex, you
> > should
> > call a method, to make clear of your intent.
> >
>
> At least to start with, I don't think we should offer separate overloading
> of $a += 1 and treat it as $a = $a +1, as the existing operator overloading
> implementation does. Operators currently only work on values that use
> by-value passing semantics, so if you write something like
>
> $b = $a = 1;
> $a += 1;
>
> then $a will be 2, but $b will be 1. Using the $a = $a + 1 expansion for
> operator overloading ensures that this is also the case for objects.
>
> Of course there are performance concerns here, and it could in some cases
> be significantly more efficient to perform an in-place modification. It is
> possible to allow that while still keeping the above semantics by only
> allowing an in-place modification if $a has no over users (something that
> we can check in the VM). But I don't think this should be part of an
> initial proposal.
>
>
> > On the topic in which order  the operators should be executed: Besides
> the
> > normal priority (defined by PHP), my code checks if the element on the
> left
> > side is an object and tries to call the appropriate magic function on it.
> > If
> > this is not possible the same is done for the right argument. This should
> > cover the most of the use cases, except some cases: Consider a expression
> > like $a / $b, where $a and $b has different classes (class A + class B).
> If
> > class B knows how to divide class A, but class A does not know about
> class
> > B, we encounter a problem when evaluating just from left to right (and
> > check
> > if the magic method exists). A solution for that would be that object $a
> > can
> > express that he does not know how to handle class B (e.g. by returning
> > null,
> > or throwing a special exception) and PHP can call the handler on object
> $b.
> > I'm not sure how common this problem would be, so I don’t have an idea
> how
> > useful this feature would be.
> >
>
> That sounds reasonable to me.
>
>
> > My proof-of-concept implementation can be found here:
> > <https://github.com/jbtronics/php-src>
> > https://github.com/jbtronics/php-src
>
>
> Unfortunately, this implementation goes in the wrong direction: PHP already
> has full internal support for operator overloading through the do_operation
> object handler. Operator overloading should be exposed to userland through
> that handler as well.
>
>
> > Here you can find some basic demo code using it:
> > <https://gist.github.com/jbtronics/ee6431e52c161ddd006f8bb7e4f5bcd6>
> > https://gist.github.com/jbtronics/ee6431e52c161ddd006f8bb7e4f5bcd6
> >
> >
> >
> > I would be happy to hear some opinions for this concept, and the idea of
> > overloadable operators in PHP in general.
> >
>
> Thanks for working on this :) I think overloaded operators are a reasonable
> addition to the language at this point. I think the main concern people
> tend to have in this area is that operator overloading is going to be
> abused (see for example << in C++). There are many very good use-cases for
> operator overloading though (as mentioned, vector/matrix calculations,
> complex, rationals, money, ...) Some of those are not common in PHP, but
> maybe the lack of operator overloading is part of the problem there ;)
>
> Regards,
> Nikita
>

Reply via email to