Re: [PHP-DEV] Operator overloading for userspace objects

2020-02-08 Thread Rowan Tommins

On 06/02/2020 20:06, Andrea Faulds wrote:
Haskell has a nice approach (probably some other languages have this 
too) where it has typeclasses that contain related operators, which 
means that e.g. if you want to overload +, your type needs to support 
Num which also contains -, *, abs, the sign function, and conversion 
from integers.

[...]
Also, Haskell also lets you just define arbitrary operators, which may 
even look the same as the built-in ones if you really want to, so 
maybe it's a bad comparison point :p



It's interesting that in this sense, Haskell supports *both* of the 
"philosophies" of overloading that I mentioned in my last message. [1]


I guess they're intended for different "levels" of programming in a sense:

- From what I've heard Haskell tries to make as little distinction 
between "built-in" and "user-defined" as possible, so like Postgres, the 
actual "normal" definitions of the operators need to be defined by some 
low-level language feature.
- On the other hand, that low-level feature is used to build a standard 
higher-level language, and that high-level language treats types as more 
important than symbols.



In general, I think PHP is quite a high-level language, and doesn't tend 
to let you re-define core concepts to build new versions of the 
language, so the type-based approach to operator overloading feels more 
in keeping to me.


If we had other low-level features - hygienic macros, meta-programming, 
meta-classes, that kind of thing - then defining new meanings for 
individual operator symbols would make more sense.



[1] https://news-web.php.net/php.internals/108347 - not showing on 
https://externals.io for some reason


Regards,

--
Rowan Tommins (né Collins)
[IMSoP]

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-02-07 Thread Andrea Faulds

Hi Johannes,

Thank you for your points! I think you point out some overlooked issues.

Johannes Schlüter wrote:

Which one is being called? - Vector's or Matrix's.  How will your
vector know about my Matrix?

The way C++ solves this is by allowing non-member functions as
operators.

  #include "vector3.h" // provides class Vector3
  #include "matrix.h"  // provides class Matrix, potentially
   //  from a different vendor

  Matrix operator*(const Vector3 , const Matrix ) {
  // I can provide  this myself if neither Vctor's nor
  // Matrix's vendor do
  return ...;
  }

  int main() {
  Vector3 vec{...};
  Matrix matrix{};

   // works
   auto result = vec * matrix;
  }


I wonder if it would be a good idea, if we do want operator overloading 
in PHP, to implement a similar mechanism for this. Perhaps type-specific 
overloads could be registered via some special function call or 
declaration, something vaguely like:


  class Vector {
public function __construct() {
  php\register_overload($this, Matrix::class, '*', function ($a, $b) {
/* multiplication implementation here */
  });
}
  }

The engine could then do type-matching for you, and would implement 
commutativity for you if the operator is commutative, so `$someVector * 
$someMatrix` would call the above function, but so would `$someMatrix * 
$someVector`. (Note: to support matrix multiplication, I guess 
commutativity must be overridable. Also, I have forgotten whether 
multiplying a matrix and a vector is commutative or not :p)


I think this approach would be less messy than having to implement full 
type matching on both sides of a type pair, for a number of reasons:


* Instead of Vector having to have an implementation of __mul which 
checks for Matrix, and Matrix having to have an implementation of __mul 
which checks for Vector, just one of these types can call 
register_overload with a single implementation (because the operation is 
commutative).
* Whether two types can be used with a particular operator is clear: 
either there is such a pair registered, or there is not, and PHP can 
give appropriate error messages. It is unlikely there will be an issue 
where one side has __mul but it just throws an exception or somethig. 
Also, in a case like `$a * $b`, $a can implement support for $b without 
$b having to support $a, while at the same time $b can implement support 
for some unrelated other type, without `$b * $a` not working (with the 
current proposal, imagine $a's __mul handler supporting $b but not 
vice-versa).
* The engine can see conflicts (one class declares an overload involving 
the other class, and vice-versa) and warn about them, rather than `$a * 
$b` silently having completely different behaviour to `$b * $a`.


This is not to say we necessarily should implement this, but it may be 
worth thinking about…


Thanks,
Andrea

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-02-06 Thread Johannes Schlüter
On Wed, 2020-01-29 at 00:14 +0100, jan.h.boeh...@gmx.de wrote:
> the last days I have experimented a bit with operator overloading in
> userspace classes (redefing the meaning of arithmetic operations like

Some historic context: I am probably the one who did operator
overloading in PHP first. Oldest trace is this post:
https://markmail.org/message/y7rq5vcd5ucsbcyb



> 
> Here you can find some basic demo code using it:
> 
> https://gist.github.com/jbtronics/ee6431e52c161ddd006f8bb7e4f5bcd6
> 

This example can be used to show a major problem for PHP doing this.

The first problem is that PHP historically had very few type
annotations making the code hard to predict, modern PHP has more of
that reducing this a bit, but the big problem remains: In PHP we can't
overload functions, thus operators have to be member functions and
therefore form a closed set.

In your example the vector3 can operate on vector3s. 

   $a = new Vector3(1, 2, 3);
   $b = new Vector3(3, 2, 1);

   $c = $a * $b;

Within Vector3 that is complete. But maths allows multiplication with
integers. So, yes, you can extend your __mul() with a check for the rhs
as you did with the is_numeric, but why would


$c = 2 * $a;

call the Vecotr3's operator function? I believe it would call integer's
operator. Which obviously doesn't exist.

But okay, let's do a hack for integer, to call the second arguments
operator if first argument is an integer.

Now I come and really like your vector3 library and create my Matrix
type. With my Matrix i want to still use your Vector3.

   include 'your/vector3.php';
   class Matrix {
  public static function __mul($lhs, $rhs) { ... }
   }

   $vec = new Vector3(...);
   $matrix = new Matrix(...);

   $result = $vec * $matrix;

Which one is being called? - Vector's or Matrix's.  How will your
vector know about my Matrix?

The way C++ solves this is by allowing non-member functions as
operators.

 #include "vector3.h" // provides class Vector3
 #include "matrix.h"  // provides class Matrix, potentially
  //  from a different vendor

 Matrix operator*(const Vector3 , const Matrix ) {
 // I can provide  this myself if neither Vctor's nor
 // Matrix's vendor do
 return ...;
 }

 int main() {
 Vector3 vec{...};
 Matrix matrix{};

  // works
  auto result = vec * matrix;
 }


To make this really work C++ has another magic, aside from function
overloading, which is ADL - Argument depending lookup, which is the
black magic of C++: If The function to be called is not only looked for
in the current or global namespace, but also the namespace of the first
Argument. So this works:


namespace JohannesCoolLibrary {
class Vector;

void func(Vector v);
Vector operator*(Vector lhs, Vector rhs);
}

namespace SomeOtherCoolThing {
JohannesCoolLibrary::Vector v1{};
JohannesCoolLibrary::Vector v2{};

v1 * v2; // will find the operator in the namespace
 // even though it's using the global name

func(v1); // will also call function from argument's namnespace
}

Without these features you can only create closed types, which
massively limit interoperability, which massively limits the use cases
for operator overloading.

With limited set of use cases, this is a rare feature, which is hard to
understand, or how many internals reads do you expect immediately know
the output of

function a($a, $b) {
return $a + $b;
}

var_dump(a([1], [2]));


johannes

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-02-06 Thread Chase Peeler
On Fri, Jan 31, 2020 at 10:55 AM Ben Ramsey  wrote:

> > Also, I want to reiterate: Any of these operations MUST be designed to
> return a new value, never modify in place.  These operators only make sense
> on value objects, not service objects, and value objects should be
> immutable.
>
> I completely agree. This was the gist of my earlier comments.
>
> Maybe we should resurrect discussion of the immutable classes and
> properties RFC: https://wiki.php.net/rfc/immutability
>
> If we add the ability to specify immutability, then we can enforce in the
> engine that the left and right operands must be immutable.
>
> For example:
>
> public function __add(immutable $left, immutable $right);
>
> Cheers,
> Ben
>
>
Ideally, I don't think the items have to be immutable. Here is a silly
use-case:
public function __add($left,$right){
$left->operatedOn++;
$right->operatedOn++;
return $left->value + $right->value;
}

However, given the nature of operator overloading, I think the users should
EXPECT what they pass in will not be changed, unless they explicitly pass
by reference. This means we'd have to "change the rules" for operator
overloading magic methods, where objects are passed by value unless
explicitly passed by reference (  public function __add(&$left, &$right) ).
I think that is an even worse idea!

So, I think you really have two options. Change the rules so that even
objects are passed by value in this specific circumstance, and there is no
ability to pass by reference. I still don't like this, because it changes
the rules for only a specific scenario, but I think it's a better option
than the one above, as well as a better option than allowing mutable
objects 100% of the time - although, I'm not totally against spelling out
in the documentation "Don't modify the items passed in or you'll get
unexpected results!"

The other options is the immutability RFC. This doesn't change the rules -
it just adds a new rule. I don't see in that RFC, though, anything about
the immutable type hints. That's really the only thing that I think is
applicable to operator overloading.



-- 
Chase Peeler
chasepee...@gmail.com


Re: [PHP-DEV] Operator overloading for userspace objects

2020-02-06 Thread Andrea Faulds

Hi,

Nikita Popov wrote:

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) show up, because someone is trying to be overly generic
in their interfaces ;)


The use-cases being diverse can be an argument against being able to 
overload individual operators — if you consider using, for example, + to 
mean something other than addition to be an issue. I don't like what 
happens in languages like C++ where you do a bitwise left-shift to 
output to a stream or divide two strings to concatenate paths.


Haskell has a nice approach (probably some other languages have this 
too) where it has typeclasses that contain related operators, which 
means that e.g. if you want to overload +, your type needs to support 
Num which also contains -, *, abs, the sign function, and conversion 
from integers. The obvious translation to PHP would be to use interfaces 
with related operations grouped. We could even support overloading some 
of the maths functions in theory (whether we should, I don't know…) Of 
course, some determined person will just implement * because it's cool 
and throw exceptions in the other methods…


Also, Haskell also lets you just define arbitrary operators, which may 
even look the same as the built-in ones if you really want to, so maybe 
it's a bad comparison point :p


Andrea

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-02-02 Thread Rowan Tommins

Hi Jan,

On 28/01/2020 23:14, jan.h.boeh...@gmx.de wrote:

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).



Thanks for bringing this up, and starting to dig into the implementation 
details.


I think there are two different philosophies of what operator 
overloading is for, which lead to different design decisions, so I think 
we should be clear which one we're embracing.


- The ability to define new types that mimic the behaviour of basic 
types, e.g. making arbitrary-precision number objects behave just like 
built-in floats and ints.
- The ability to attach an operator to any type with a domain-specific 
meaning, like a method with a funny-looking name, e.g. using . to 
represent "dot-product" within a matrix arithmetic library, rather than 
tying it to the meaning "concatenation".



If you think of operator overloading as mimicking existing types, some 
possible implications:


- Justifying every overload offered with an explicit use case
- Overloading named operations, not operator symbols - e.g. "__add" 
rather than "operator+"
- Requiring operations to be grouped - e.g. "type classes", where you 
can't just implement "add", you have to implement everything needed to 
"behave as a number"; in PHP terms, an interface rather than independent 
magic methods
- Deriving additional operations from those implemented - e.g. defining 
"compareTo" is enough to implement < <= == != >= and >; or implementing 
"add" is enough to derive multiplication by an integer ($a * 3 => $a + 
$a + $a) and even exponentiation ($a ** 3 = $a * $a * $a)



If you think of operator overloading as a tool for domain-specific 
language design, the implications are rather different:


- Treating the symbol as the important thing, not its traditional 
meaning - e.g. "operator+" rather than "__add"
- Only restricting operators from overloading where there is some 
over-riding reason, e.g. reserving the meaning of === but allowing ~ 
regardless of whether "bit-wise operations" have any particular use case
- Allowing the user to create entirely new operators, with their own 
meanings; Postgres, for instance, defines an operator as a sequence of 1 
to 63 of the characters + - * / < > = ~ ! @ # % ^ & | ` ? with a few 
technical restrictions; Raku/Perl6 allows pretty much any Unicode character
- Allowing every operator to be implemented separately, with whatever 
result is desired; if . can mean "dot product", there's no reason <= 
couldn't mean "derive from"
- Not assuming any relationship between operators once they've been 
overloaded; so implement <=> doesn't imply availability of < and > 
unless the user has opted into that relationship (e.g. using a Trait to 
import a definition for additional overloads)



Regards,

--
Rowan Tommins (né Collins)
[IMSoP]

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



RE: [PHP-DEV] Operator overloading for userspace objects

2020-02-01 Thread jan.h.boehmer
On Sat, Feb 1, 2020 10:22 AM  wrote:
> Looks much better! If you submit a pull request, I can leave some more 
> detailed comments.

Okay, I will submit a pull request with my changes.
 
> If you would like to start an RFC on this topic, please sign up for a wiki 
> account (https://wiki.php.net/rfc/howto) and send me your username.

My Wiki account name is jbtronics.

Thank you,
Jan Böhmer

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-02-01 Thread Nikita Popov
On Thu, Jan 30, 2020 at 10:22 PM  wrote:

> > 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.
>
> I have made another implementation (
> https://github.com/jbtronics/php-src/tree/operator_overloading) which
> provides an standard handler for do_operation, which calls the functions in
> user space.
>

Looks much better! If you submit a pull request, I can leave some more
detailed comments.


> I also removed the __compare magic function from my implementation, so
> this can be handled separately.
>
> Another thing: What are your opinions on overload the bitwise not operator
> (~)? My implementations offers every other bitwise operator and this one
> would complete the set of bitwise operators. On the other hand unary
> operators does not have much use for objects and maybe encourage people
> using them as "shortcut" for calling things on the object, where an
> explicit method call would make the intend function more clear.
>

Don't really see a reason not to support it. We do overload the bitwise not
operator for GMP objects, and it would be equally applicable to other
"integer" style objects.

If you would like to start an RFC on this topic, please sign up for a wiki
account (https://wiki.php.net/rfc/howto) and send me your username.

Nikita


Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-31 Thread Larry Garfield
On Fri, Jan 31, 2020, at 11:32 AM, Mike Schinkel wrote:
> > On Jan 31, 2020, at 10:41 AM, Larry Garfield  wrote:
> > 
> > I cannot speak to the implementation details.  From a design perspective, I 
> > am tentatively positive on operator overloading, with separate method for 
> > each operator, BUT, the big question for me is the rules around type 
> > compatibility.
> 
> I have avoided commenting on this thread to see where it would lead.   
> I have been surprised so many here are embracing operator overloading.  
> 
> My experience taught me operator overloading has been added to 
> languages because "it seemed like a good idea at the time." But it is 
> now considered to be harmful, by many:
> 
> - https://www.quora.com/What-are-the-pitfalls-of-operator-overloading
> - 
> https://cafe.elharo.com/programming/operator-overloading-considered-harmful/
> - 
> https://www.oreilly.com/library/view/sams-teach-yourself/0672324253/0672324253_ch21lev1sec4.html
> - https://en.wikipedia.org/wiki/Operator_overloading#Criticisms
> - 
> https://www.jarchitect.com/QACenter/index.php?qa=53_1=overload-operators-special-circumstances-defined-literals
> 
> (Ruby's ability for developers to redefine the entire language is an 
> especially chilling example of the concepts of operator overloading 
> taken to the extreme: https://dev.to/jimsy/please-stop-using-ruby-4lf1) 
> 
> That said, I will not protest further if others still really feel 
> strongly about adding operator overloading after reviewing those 
> criticisms.

Those are valid points.  (Hence my "tentatively.")  Operator overloading is one 
of those features that when used well can be really really nice, but is really 
easy to use badly (in which case it's really really not nice).

In all honesty, I'd probably be more excited about bringing back comparison 
overloading (__compare() and __equals()) than overriding arithmetic.  Unless we 
could get some kind of bind operator, but that's probably asking for trouble. 
:-)

> > Also, I want to reiterate: Any of these operations MUST be designed to 
> > return a new value, never modify in place.  These operators only make sense 
> > on value objects, not service objects, and value objects should be 
> > immutable.
> > 
> > Which means that there is no __addEquals() method, just _add(), and we 
> > continue with that being isomorphic to $a = $a + $b;, the behavior of which 
> > is readily predictable.
> 
> Immutability is a great feature from functional programming. But I 
> think it is orthogonal to operator overloading as it would be 
> (relatively) easy to implement an __add() method but how would PHP 
> enforce that __add() would not be able to mutate state?

Currently it cannot.  That's another point of concern.  We could at best 
document it and put "please please don't modify the object" in the docs, but 
that would probably work just as well as you think it would...

All of this is pointing in the "we need a language construct for value objects" 
direction, which I believe would be highly useful but I don't know how we'd do 
it nicely.  (Mainly, how to handle what PSR-7 does with withX() type methods, 
which are clunky but the best we can do without some really funky new syntax.)

--Larry Garfield

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-31 Thread jan.h.boehmer
> I cannot speak to the implementation details.  From a design perspective,
I am tentatively positive on operator overloading, with separate method for
each operator, BUT, the big question for me is the rules around type
compatibility.
>
> Can you only compare 2 of the same type?  What about subclasses?  Can that
differ if a subclass overrides that method?  What happens to commutativity
then?  Can you compare based on an interface?

I do not think the types should be restricted at all. For a numeric-like
object like an money value, adding an scalar like an integer or float is
quite useful (e.g. $a + 2.5), for things like vectors this would be not
resolvable (you can only add between vectors, while multiplication with an
scalar is valid). In my opinion the object should determine the operands
types and decide if it can handle it or not (and then throwing an
exception). As long as PHP does not allow function overloading with
different types (like C# does), I see no other possibility except deciding
on runtime if the type is supported.

For sub classes this is more difficult. I guess in the most use cases
defining a good operation handler in a sub class is sufficient, so maybe the
operation handlers could be required to be final. Another possibility would
be to let the user handle this situation completely, even if this could lead
to undesired behavior.
In my opinion the most elegant solution, would be if an operator handler
could somehow signal that it does not support the type passed (maybe by
returning null, or throwing a special OperandTypeNotSupportedException), so
that PHP can try to call the operation handler on the right operand (that is
one of the reasons I like passing both operands to a static handler).

> Also, I want to reiterate: Any of these operations MUST be designed to
return a new value, never modify in place.  These operators only make sense
on value objects, not service objects, and value objects should be
immutable.

I agree with that. The best solution here would be  an integrated support
for immutable value objects (which could become quite complex on its own),
but I wonder if it would be sufficient if copies of the objects instances
are passed to the operator handler. The user could then change the scalar
properties of the object like he wants, without changing the operands
objects.

> Frankly I'd avoid bitwise operators entirely for now.  I'm not even sure
how you'd use those...

They could be maybe useful for mathematical objects, that define more than
the four basic arithmetic operators (like the cross vs dot on vectors, or
tensor product) or four things like length-safe binary number objects. Also
I would say they are not used very often in normal PHP, so redefining them
as custom operators would be less confusing, then using other operators for
that.
But I can understand everyone who dislike the idea of overloading them, for
the reason that their used could become too confusing. If there is to be an
voting on an RFC, maybe it should be split into a voting on the arithmetic
operators/concatenation and a voting on the bitwise operators.

Greetings,
Jan Böhmer

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-31 Thread Ben Ramsey
> If we still want operator overloading and we want to force operator 
> overloading to require immutability, I believe that means we would need an 
> immutability RFC to be approved (and implemented?) before operator 
> overloading requiring immutability could be approved.  Something like this:


For reference, immutability has been proposed in the past, but I’m not sure 
where it landed. It looks like it fizzled out.

* https://wiki.php.net/rfc/immutability
* https://externals.io/message/94913
* https://externals.io/message/96919
* https://externals.io/message/97355
* https://externals.io/message/101890
* https://externals.io/message/81426

I agree with you that I think we need to accept an immutability RFC before 
operator overloading (requiring immutability) can be approved.

I also believe operator overloading should require immutability.

Cheers,
Ben



signature.asc
Description: Message signed with OpenPGP


Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-31 Thread Mike Schinkel
> On Jan 31, 2020, at 10:41 AM, Larry Garfield  wrote:
> 
> I cannot speak to the implementation details.  From a design perspective, I 
> am tentatively positive on operator overloading, with separate method for 
> each operator, BUT, the big question for me is the rules around type 
> compatibility.

I have avoided commenting on this thread to see where it would lead.   I have 
been surprised so many here are embracing operator overloading.  

My experience taught me operator overloading has been added to languages 
because "it seemed like a good idea at the time." But it is now considered to 
be harmful, by many:

- https://www.quora.com/What-are-the-pitfalls-of-operator-overloading
- https://cafe.elharo.com/programming/operator-overloading-considered-harmful/
- 
https://www.oreilly.com/library/view/sams-teach-yourself/0672324253/0672324253_ch21lev1sec4.html
- https://en.wikipedia.org/wiki/Operator_overloading#Criticisms
- 
https://www.jarchitect.com/QACenter/index.php?qa=53_1=overload-operators-special-circumstances-defined-literals

(Ruby's ability for developers to redefine the entire language is an especially 
chilling example of the concepts of operator overloading taken to the extreme: 
https://dev.to/jimsy/please-stop-using-ruby-4lf1) 

That said, I will not protest further if others still really feel strongly 
about adding operator overloading after reviewing those criticisms.

> Also, I want to reiterate: Any of these operations MUST be designed to return 
> a new value, never modify in place.  These operators only make sense on value 
> objects, not service objects, and value objects should be immutable.
> 
> Which means that there is no __addEquals() method, just _add(), and we 
> continue with that being isomorphic to $a = $a + $b;, the behavior of which 
> is readily predictable.

Immutability is a great feature from functional programming. But I think it is 
orthogonal to operator overloading as it would be (relatively) easy to 
implement an __add() method but how would PHP enforce that __add() would not be 
able to mutate state?

Consider the following.  How would __add() stop the mutating happening in 
$foo->bar->increment_ops()?  

class Bar {
   private $_op_count = 0;
   function increment_ops() {
  $this->_op_count++;
   }
}
class Foo {
   public $value;
   public $bar;
   function __construct( int $value ) {
  $this->value = $value;
   }
   function __add( Foo $foo ): Foo {
  $this->bar->increment_ops();
  return new Foo( $this->value + $foo->value );
   }
}
$foo = new Foo(10);
$foo->bar = new Bar();
$foo = $foo + new Foo(5);
echo $foo->value;

I am sure it would be _possible_ to stop it, but I do not think it is trivial 
to architect nor implement. Given that I believe immutability would need to be 
implemented as an independent feature and not as an aspect of operator 
overloading. 

If we still want operator overloading and we want to force operator overloading 
to require immutability, I believe that means we would need an immutability RFC 
to be approved (and implemented?) before operator overloading requiring 
immutability could be approved.  Something like this:

class Bar {
   private $_op_count = 0;
   immutable function increment_ops() {
  global  $foo;
  $foo = new Foo();<== Compile error!
  $this->_op_count++;   <== Compile error!
   }
}

> I've actually been wondering lately if we shouldn't create an entirely 
> separate data structure for value objects...

+1 for that. 

-Mike

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-31 Thread Benjamin Morel
I like this whole operator overloading thing. I would probably use it in
brick/math  and brick/money
 to replace verbose `->plus()`,
`->multipliedBy()` etc. calls.

> Can you only compare 2 of the same type?  What about subclasses?  Can
that differ if a subclass overrides that method?  What happens to
commutativity then?  Can you compare based on an interface?

I think that this should behave exactly the same as if you replaced `$a +
$b` with `$a->__add($b)` in your code. Nothing more, nothing less. The
result will depend on whether you type-hinted your magic method or not.

> These operators only make sense on value objects, not service objects,
and value objects should be immutable.

Indeed, we would need to make it clear that the operation must not modify
the value of the current object, that should be effectively treated as
immutable.
Because it will probably be hard for the engine to enforce this, what about
using the same convention I use in my libraries, i.e. `plus()` instead of
`add()`, `dividedBy()` instead of `divide()`, etc.?

This would translate to magic methods such as:

__plus()
__minus()
__multipliedBy()
__dividedBy()

Benjamin


Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-31 Thread Ben Ramsey
> Also, I want to reiterate: Any of these operations MUST be designed to return 
> a new value, never modify in place.  These operators only make sense on value 
> objects, not service objects, and value objects should be immutable.

I completely agree. This was the gist of my earlier comments.

Maybe we should resurrect discussion of the immutable classes and properties 
RFC: https://wiki.php.net/rfc/immutability

If we add the ability to specify immutability, then we can enforce in the 
engine that the left and right operands must be immutable.

For example:

public function __add(immutable $left, immutable $right);

Cheers,
Ben



signature.asc
Description: Message signed with OpenPGP


Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-31 Thread Larry Garfield
On Thu, Jan 30, 2020, at 3:22 PM, jan.h.boeh...@gmx.de wrote:
> > 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.
> 
> I have made another implementation 
> (https://github.com/jbtronics/php-src/tree/operator_overloading) which 
> provides an standard handler for do_operation, which calls the 
> functions in user space.
> 
> I also removed the __compare magic function from my implementation, so 
> this can be handled separately.

I cannot speak to the implementation details.  From a design perspective, I am 
tentatively positive on operator overloading, with separate method for each 
operator, BUT, the big question for me is the rules around type compatibility.

Can you only compare 2 of the same type?  What about subclasses?  Can that 
differ if a subclass overrides that method?  What happens to commutativity 
then?  Can you compare based on an interface?

Examples:

class Money {

  public function __add(Money $m) { ... }

}

class Dollar extends Money {
  public function__add(Money $m) { ... }
}

class Euro extends Money {
}


$m = new Money(5);
$d = new Dollar(10);
$e = new Euro(15);



What should happen in each of these cases?

$m + $d;
$d + $m;
$m + $e;
$e + $m;
$d + $e;

Or similarly, is this allowed:

interface Money {
  public function __add(Money $m);
}

There's a lot of very tricksy logic here to work out in terms of what makes 
sense to do before we could consider it.  That logic may already have been 
figured out by another language (Python, C#, etc.) in which case I'm perfectly 
happy to steal their logic outright if it makes sense to do so.  It's worth 
investigating before we go further to see what the traps are going to be.

Also, I want to reiterate: Any of these operations MUST be designed to return a 
new value, never modify in place.  These operators only make sense on value 
objects, not service objects, and value objects should be immutable.

Which means that there is no __addEquals() method, just _add(), and we continue 
with that being isomorphic to $a = $a + $b;, the behavior of which is readily 
predictable.

I've actually been wondering lately if we shouldn't create an entirely separate 
data structure for value objects that helps enforce that difference of 
expectation.  (Similar to shapes in Hack, or records or structs in various 
other languages.)


> Another thing: What are your opinions on overload the bitwise not 
> operator (~)? My implementations offers every other bitwise operator 
> and this one would complete the set of bitwise operators. On the other 
> hand unary operators does not have much use for objects and maybe 
> encourage people using them as "shortcut" for calling things on the 
> object, where an explicit method call would make the intend function 
> more clear.

Frankly I'd avoid bitwise operators entirely for now.  I'm not even sure how 
you'd use those...

--Larry Garfield

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



RE: [PHP-DEV] Operator overloading for userspace objects

2020-01-30 Thread jan.h.boehmer
> 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.

I have made another implementation 
(https://github.com/jbtronics/php-src/tree/operator_overloading) which provides 
an standard handler for do_operation, which calls the functions in user space.

I also removed the __compare magic function from my implementation, so this can 
be handled separately.

Another thing: What are your opinions on overload the bitwise not operator (~)? 
My implementations offers every other bitwise operator and this one would 
complete the set of bitwise operators. On the other hand unary operators does 
not have much use for objects and maybe encourage people using them as 
"shortcut" for calling things on the object, where an explicit method call 
would make the intend function more clear.

Regards,
Jan

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



RE: [PHP-DEV] Operator overloading for userspace objects

2020-01-29 Thread jan.h.boehmer
> 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.

I understand your point. There was already an RFC with an similar idea 
(https://wiki.php.net/rfc/comparable). I think the idea of having an comparable 
interface could be really useful for things like sorting algorithms (so these 
could sort any comparable object). The case that structures must not define an 
order (but can have equality) is a good point, maybe this could be solved with 
two interfaces Comparable (which defines the spaceship operator) and another 
one like Matchable or Equalable (which only defines an is_equal function). I 
would not split the comparison operators any further (the RFC mentioned above 
even suggested to overload the not equal operator) or we end up with 
situations, where $a!=$b is not the same as !($a==$b), which would make the 
code using it very difficult to understand.

It is maybe reasonable to split operator and comparison overloading into 
different RFCs so they can be discussed separately. But if PHP decides to offer 
operation overloading it should also offer a possibility to compare custom 
objects, or the operation overloading looses some of its intended convenience 
(like the situation in PHP 7.0 where you could define scalar type hints, but 
could not allow passing null easily).

> 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.

I agree. If there is real need for this case, it could be implemented later.

> 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.

I have seen this mechanism too late, and I have to understand a bit more how it 
works exactly, but I agree that this internal operator overloading mechanism 
should be used. I think it should be the goal that internal and userspace 
classes should appear the same to the user in points of the operator 
overloading, so an user can just call for example parent::__add() if he is 
extending a PHP class (e.g. Carbon does that for the datetime class). I will 
try to build an implementation using the do_operation handler, when I have time.

> 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 ;)

Ultimately we cannot really control how people will end up using the operation 
overloading, but in my opinion the benefits outweighs the drawbacks (also 
hopefully nobody would be insane enough to replace the print function with << 
;) ).
With FFI-bindings it would be possible to build cool math/calculation libraries 
(similar to numpy in python), that can be accessed easily via PHP and does big 
calculations in native speed. I don’t think PHP will become an scientific used 
language like python, but sometimes some higher math function in PHP could be 
helpful. Also at least the handling of money values is quite common in web 
applications.

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-29 Thread Olumide Samson
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,  wrote:

> On Wed, Jan 29, 2020 at 12:14 AM  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), which was discussed a
> bit
> > (
> >  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) 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 

Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-29 Thread Nikita Popov
On Wed, Jan 29, 2020 at 12:14 AM  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), which was discussed a bit
> (
>  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) 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 

Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-28 Thread Ben Ramsey
> On Jan 28, 2020, at 17:55, Michael Cordover  wrote:
> 
> On Tue, Jan 28, 2020, at 18:47, Ben Ramsey wrote:
>> If you take mutation off the table, then things become easier, IMO. We
>> only need two magic methods:
>> 
>> * __toInteger(): int
>> * __toFloat(): float
>> 
>> Then, in any mathematical context, PHP could call the appropriate
>> method and use the number returned in the calculation.
> 
> I don't think this is enough to make operator overloading useful, even 
> without mutation.
> 
> For example, the result of TimeInterval(1, 'ms') + TimeInterval(3, 'days') 
> requires more information that we'd get out of __toInteger or __toFloat, but 
> could still be a useful operation to perform, and ought to return a new 
> TimeInterval (not an int). There are many of these tagged-number types where 
> overloading would be helpful.


I just remembered this extension from a few years back. It’s no longer 
maintained, but it might help your efforts: 
https://github.com/php/pecl-php-operator

Cheers,
Ben



signature.asc
Description: Message signed with OpenPGP


Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-28 Thread Michael Cordover
On Tue, Jan 28, 2020, at 18:47, Ben Ramsey wrote:
> If you take mutation off the table, then things become easier, IMO. We 
> only need two magic methods:
> 
> * __toInteger(): int
> * __toFloat(): float
> 
> Then, in any mathematical context, PHP could call the appropriate 
> method and use the number returned in the calculation.

I don't think this is enough to make operator overloading useful, even without 
mutation.

For example, the result of TimeInterval(1, 'ms') + TimeInterval(3, 'days') 
requires more information that we'd get out of __toInteger or __toFloat, but 
could still be a useful operation to perform, and ought to return a new 
TimeInterval (not an int). There are many of these tagged-number types where 
overloading would be helpful.

- mjec

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



Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-28 Thread Ben Ramsey
> On Jan 28, 2020, at 17:14,   
> 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), which was discussed a bit (
>  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.
> 
> 
> 
> 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).
> 
> 
> 
> 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).
> 
> 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).
> 
> 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

Re: [PHP-DEV] Operator overloading for userspace objects

2020-01-28 Thread David Rodrigues
I think that the left operand is the "owner", the magic method handler,
while the right operand is the argument.

So for $object * 5, we will have:

// $object instance
public function __multiply($number): self {
return $this->multiply($number);
}

But for 5 * $object we will have an error. Call order should be respected
now once that will be impossible you have $objectA * $objectB without
defines a priority (the main handler).


--
Atenciosamente,
David Rodrigues


Em ter., 28 de jan. de 2020 às 20:14,  escreveu:

> 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), which was discussed a bit
> (
>  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.
>
>
>
> 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).
>
>
>
> 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).
>
> 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).