Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-23 Thread Pierre

Le 06/08/2021 à 18:34, Jordan LeDoux a écrit :

Hey all,

...


Hello,

I'm sorry I couldn't answer the last few weeks I was on vacation.

I just wanted to say, I'm opposed to user-land operator overloading for 
a few reasons:


 * it may produce shorter, simpler code, but it hides the real logic
   behind,
 * not all mathematical arithmetic operators have a semantic meaning
   for let's say, collections: it's not evident to me that "/" means
   partition (even thought the "+" for union is trivial),
 * they are hundreds different operations on collections which have a
   common taxonomy in many languages, there will never be enough
   operators for all, we will end up with Frankenstein API's where
   there will be operators for some operations, and methods for others,
 * methods in plain english (or whatever is your language) are always
   more readable in the end,
 * you can CTRL+click to navigate (in a decent IDE) on a method call,
   not on an operator,
 * step-debugging will be a bumpy ride,
 * some people will use them good, many will misuse them, some will do
   evil with those,
 * and hell, if "->" doesn't mean "access that object member" anymore,
   but "hey, the implementor could do anything at all instead", sky
   will fall upon us.

I'm not sure the benefice-risk ratio is good enough.

That said, in the other side, I'm +1 with equals(), compareTo() and 
those kind of magic methods for the "==" and comparison functions, this 
is something that PHP lacks, but I'm unsure this worth making all 
operators user-land overridable.


I'm always favorable to something that makes the code being semantically 
and non-ambiguous to read, and in my opinion userland operators create 
more mess than they solve, they basically encourage people to make 
non-readable stupid shortcuts in their code.


Best regards,

Pierre



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-23 Thread Dik Takken
On 08-08-2021 09:41, Jordan LeDoux wrote:
> Off the top of my head here are some of the use cases that I think benefit
> greatly from this:
> 
> - Complex number objects
> - Fractions objects
> - Matrix objects (math)
> - Vector objects (math)
> - Time/Date intervals
> - Collections
> - Arbitrary precision numbers (which are usually represented as a string in
> PHP)

Hi Jordan,

I would like to point out another interesting use case that I have seen
in the Python world: Query builders. In that use case, operator
overloads are used to create database filtering expressions for example,
allowing one to write:

db.products.filter(db.products.price < 100)

Here db.products.price is an object representing a database column
implementing the __lt__ method, overloading the < operator. This method
returns an object representing a database filtering expression, which
gets passed to the filter() method.

So basically, this would allow for writing expressions in plain PHP and
have them translated into other languages under the hood.

The use case does require that operator overloads are allowed to return
any kind of value they wish.

Regards,
Dik Takken

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-11 Thread Mike Schinkel
> On Aug 11, 2021, at 5:25 AM, Jordan LeDoux  wrote:
> 
> I want to avoid this. :) The implementations in my actual math libraries are 
> much more thorough and thought out. This is an example. If people want to see 
> something that is closer to what would actually be done in a library, they 
> should look at an actual library. So instead, that's what I'll link to:
> 
> Here's the multiply method: 
> https://gist.github.com/JordanRL/98cceb392ba5ba943462fe574f18de51 
> 
> Here's the translateToParts method: 
> https://gist.github.com/JordanRL/2c67acb3b5d3069c3a4d2f0448a480d1 
> 
> Here's the PolynomailFunction: 
> https://gist.github.com/JordanRL/673e357e7f5cf63bd4554fb3161c026b 
> 
> 
> You can think of ImmutableDecimal as Real|Imaginary, but with methods such as 
> $obj->isReal() and $obj->isImaginary() on it.
> 
> This is just for the __mul() method. The intent of this example is to show 
> the nature of the problems being solved, not to show the actual solutions. 
> Think of this as syntactically correct pseudo-code, not an actual 
> implementation.

Well, I refactored not to provide an actual implementation but to try to show 
the problems being solved in a manner that could be more easily understood. But 
it is your RFC, so it's yours to decide how code is presented.



Anyway, I'll summarize as I am going to try to wrap up my participation in this 
topic, at least for now:

1. I argue that it would likely be a mistake to add general purpose operator 
overloading to classes in PHP (or at least before a lot of experience with #2.)

2. However, I recognize there are use-cases which beg for operator overloads I 
think PHP. And I believe those use-cases are finite: money, the math examples, 
and units[1] being three (3) subsets.  I think PHP would be better served by 
adding those use-cases as standard library classes[2] instead of adding general 
purpose operator overloading to the language.

3. However, *if* there is strong consensus that we should add general purpose 
operator overloading then I argue that it should be limited to "value" objects, 
which currently would mean only classes where all public and protected 
properties are read-only[3].

4. And even if we do #3 that is no reason for us not to consider also doing (at 
least some of) #2.

#fwiw

-Mike



[1] https://www.nist.gov/pml/weights-and-measures/metric-si/si-units 


[2] I mean, how great would it be to have a Length class with unit conversions 
built into PHP?  Or a Money class that all libraries that deal with Money would 
be able to interoperate with? Having these non-changing concepts built-in to 
PHP would be a strong reason developers to choose PHP over other options like 
Node where they have to manage tons of ever-changing and incompatible 3rd party 
dependencies. Better that than 10+ different userland implementations of the 
same bedrock concepts, many of which are incomplete and all of which are 
incompatible with each other.

[3] Yes, private property values could be changed by methods and thus leak to 
the outside. But that could be considered an anti-pattern. If said private 
property(s) (partially) represent the state of the object and are not readonly 
then we could simply recognize that as an unchecked bad practice.



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-11 Thread Jordan LeDoux
On Wed, Aug 11, 2021 at 1:42 AM Mike Schinkel  wrote:

>
> It that what you envision?  To create a ComplexNumber() do I first need to
> wrap in Real() and in Imaginary()?  Or where you intending I could just
> pass numeric literals? If yes, PhpStorm said your type hints did not allow
> it.
>
>
In this particular implementation yes, however that is mainly to solve the
problem of what happens when you add an Imaginary and Real together, which
won't result in either class but instead ComplexNumber. It also allows
SimpleNumber to stand in for the typedef Real|Imaginary, because I wanted
this example to use only the features I plan to add in my RFC + 8.1. That
means no combination types (SimpleNumber)|int and no typedefs.


>
> Yes, the complexity overwhelmed me at first glance, but I don't think it
> needs to be so complex, which I will get to below.
>
>
It doesn't need to be, no. But then I wrote the implementation in about 30
minutes. The actual implementations in my Complex Number library took me
several months.


>
> 1. In your examples would I use `SimpleNumber` anytime I see
> `Imaginary|Real`?
>
>
You can when the argument or the statement could accept either, then use
the concrete implementations when you need to differentiate. This is a
method of getting around the absence of typedefs in PHP.


> 2. I notice in SimpleNumber methods you pass SimpleNumber $self as a first
> parameter to __add() and __mul() and in ComplexNumber you pass
> ComplexNumber $self as a first parameter, but in ComplexNumber you never
> use it. Obviously the __add() and __mul() signatures would need to be
> equivalent, but I didn't grok why you didn't just use $this instead of
> $self so I omitted that parameter in my fork.
>
>
This is to remain consistent with the RFC's proposed (current) syntax,
which covers use cases that don't apply to this particular example. $self
is useful because it can be type hinted as an argument. So SimpleNumber
provides the __add() and __mul() methods for Real and Imaginary, and it
typehints $self as SimpleNumber. However, for the __mod() method for
example, the SimpleNumber class could type hint the argument as Real
instead, since taking the modulo of an imaginary number might be something
you error on instead. In this case, PHP would give the much more useful
error related to type inconsistency, instead of something like 'Operator
not supported' when used with an Imaginary instance, as it would inherit
the $self instanceof Real restriction from SimpleNumber.


> 3. I'm not sure why we even need a `Real` class, other than the fact PHP
> doesn't (currently?) support operations on numeric literals and imaginary
> numbers. Check my logic here but if PHP understood complex numbers then
> `Real` could just be a `float`. But with just userland operator overloading
> we have to wrap a float inside an instance of Real, right?
>
>
In this case, the reason for Real is so that custom logic around
combination with ComplexNumber and Imaginary instances can be implemented.
If there were literals for both imaginary numbers and complex numbers, and
they behaved correctly native with ints and floats, then no, there'd be no
need. But again, I'm not entirely certain that putting an entire complex
number library into core is necessary or preferrable.


> 4. It looks like you added a $left = bool parameter but never used it.  I
> assume the intent is that PHP for some reason might want to convert `$x +
> $y` to $y->__add($x,true)?  When would it need that?  Seems that the $left
> parameter just makes the signature more complex.  I dropped it from my fork.
>
> Also, this really cries out for userland type definitions and type aliases
> (which can and IMO should be two distinctly different things, btw.):
>
>
Yes, that is also something that I have heavily considered doing an RFC
for, however I highly suspect that others will attempt them and be more
qualified to tackle those issues than I would. You assumed the purpose of
$left correct (which is also covered in the RFC doc in the same repository,
which I highly suggest you read since it seems it's generating some
avoidable confusion for you here).


>
> But it would be nice if you could also stub out __pow() and any others
> abstract methods so the full list of expected operations and their
> parameters.
>
>
I mean... I'll just link to my actual library for that. It requires so much
more external logic. I would need to write the function that translates
between polar and cartesian coordinate systems, then I would need to write
the trigonometry equation that allows you to handle complex numbers to a
complex power. For complex numbers to a real power I'd need to write a
generalized FOIL function, and then for imaginary powers I'd need to handle
rotations around the origin.

If you are actually curious about the math, (and it is very fascinating to
me so I understand), I'd suggest that you look at library implementations
of pow for complex numbers. I really don't think 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-11 Thread Mike Schinkel
> On Aug 11, 2021, at 12:06 AM, Jordan LeDoux  wrote:
> 
> Here is a quick and dirty example of just the complex number use case. It
> assumes that the operator overloads already are built in. A couple of
> things of note:

Excellent. Thank you for taking the time to do this.  Very helpful.

One thing I looked for at first but did not find was an actual example of how 
you would use them vs. how they would be implemented.  So I forked it and 
created such a file to see if I could understand how they would be used:

https://github.com/mikeschinkel/operator-overloading-rfc/blob/master/use-cases/complex-numbers/example.php

It that what you envision?  To create a ComplexNumber() do I first need to wrap 
in Real() and in Imaginary()?  Or where you intending I could just pass numeric 
literals? If yes, PhpStorm said your type hints did not allow it.

> 1. The actual mathematical logic to cover all the possible input and return
> types is extensive. Though the execution time and complexity are quite
> limited, the code complexity is high due to the number of conditionals.

Yes, the complexity overwhelmed me at first glance, but I don't think it needs 
to be so complex, which I will get to below.

> 2. I chose to implement the various operator overload functions in
> different ways to illustrate different methods that might accomplish the
> same task in userland code. For instance, in some cases I typed against the
> SimpleNumber abstract, while in others I expanded SimpleNumber out into its
> concrete implementations, Real and Imaginary.

Yeah, that kind of threw me to, because I looked at the code before I read your 
email.

And it still throws me because I'm not 100% clear how SimpleNumber is supposed 
to behave. 

1. In your examples would I use `SimpleNumber` anytime I see `Imaginary|Real`?

2. I notice in SimpleNumber methods you pass SimpleNumber $self as a first 
parameter to __add() and __mul() and in ComplexNumber you pass ComplexNumber 
$self as a first parameter, but in ComplexNumber you never use it. Obviously 
the __add() and __mul() signatures would need to be equivalent, but I didn't 
grok why you didn't just use $this instead of $self so I omitted that parameter 
in my fork.

3. I'm not sure why we even need a `Real` class, other than the fact PHP 
doesn't (currently?) support operations on numeric literals and imaginary 
numbers. Check my logic here but if PHP understood complex numbers then `Real` 
could just be a `float`. But with just userland operator overloading we have to 
wrap a float inside an instance of Real, right? 

4. It looks like you added a $left = bool parameter but never used it.  I 
assume the intent is that PHP for some reason might want to convert `$x + $y` 
to $y->__add($x,true)?  When would it need that?  Seems that the $left 
parameter just makes the signature more complex.  I dropped it from my fork.

Also, this really cries out for userland type definitions and type aliases 
(which can and IMO should be two distinctly different things, btw.):

`SimpleNumber|ComplexNumber|int|float $other`

> 3. I only implemented the _add() and __mul() methods for this example, as
> the reality is that getting into some of the more complex operations would
> be so much code that it wouldn't be a digestible example. The __pow()
> method for ComplexNumber would be in excess of 100 lines and also require a
> polar coordinate representation within the class, for instance.

Sure.  

But it would be nice if you could also stub out __pow() and any others abstract 
methods so the full list of expected operations and their parameters. 

BTW, when I asked I wasn't expecting to see an implementation for any of the 
methods, I was just asking for an interface.  You went above and beyond that.

And, since you are writing code that won't run anyway, why not go ahead and 
assume a `typedef`? That would greatly reduce the visual complexity of your 
example:

typedef Number: Imaginary|Real|SimpleNumber|ComplexNumber|int|float;

> This isn't a working implementation, in that this code will produce errors
> if run in PHP (due to the absence of operator overloads). Please note that
> if we were to go the route of creating domain-specific classes to cover
> this use case, the actual classes would be many, many times longer than
> this.

Yes, of course.

> This is some of the simplest logic involved in this particular use
> case, which is why I chose it as the example, and that perhaps illustrates
> why I am willing to explore such objects but do not believe they are the
> best choice at this time.

So I promised to explain how to simplify the logic. This has nothing to do with 
operator overloads so anyone reading who is only interested in the RFC can stop 
reading now.

-Mike



There is a concept called the "Happy Path"[1] which is " is a default scenario 
featuring no exceptional or error conditions." It is often used to refer to 
testing, but there is an emerging trend where people are arguing that 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-10 Thread Jordan LeDoux
On Tue, Aug 10, 2021 at 8:46 PM Mike Schinkel  wrote:

>
> Either way if PHP can identify a value object then it could limit operator
> overloads to just classes that are value objects by whatever approach PHP
> chooses to distinguish.
>
>
> -Mike
> [*] Ironically I mentioned you because I thought you would be appreciate
> seeing another reason PHP could benefit from value objects. But as they
> say, no good deeds go unpunished.
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>
Here is a quick and dirty example of just the complex number use case. It
assumes that the operator overloads already are built in. A couple of
things of note:

1. The actual mathematical logic to cover all the possible input and return
types is extensive. Though the execution time and complexity are quite
limited, the code complexity is high due to the number of conditionals.
2. I chose to implement the various operator overload functions in
different ways to illustrate different methods that might accomplish the
same task in userland code. For instance, in some cases I typed against the
SimpleNumber abstract, while in others I expanded SimpleNumber out into its
concrete implementations, Real and Imaginary.
3. I only implemented the _add() and __mul() methods for this example, as
the reality is that getting into some of the more complex operations would
be so much code that it wouldn't be a digestible example. The __pow()
method for ComplexNumber would be in excess of 100 lines and also require a
polar coordinate representation within the class, for instance.

This isn't a working implementation, in that this code will produce errors
if run in PHP (due to the absence of operator overloads). Please note that
if we were to go the route of creating domain-specific classes to cover
this use case, the actual classes would be many, many times longer than
this. This is some of the simplest logic involved in this particular use
case, which is why I chose it as the example, and that perhaps illustrates
why I am willing to explore such objects but do not believe they are the
best choice at this time.

https://github.com/JordanRL/operator-overloading-rfc/tree/master/use-cases/complex-numbers

Jordan


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-10 Thread Mike Schinkel
> On Aug 10, 2021, at 10:22 AM, Larry Garfield  wrote:
> 
> Point of order: I do not support a dedicated value-object/data-object 
> construct, and have said so explicitly.  I support targeted tools that make 
> using objects in that fashion cleaner and more robust.  (readonly, asymmetric 
> visibility, clone-with, etc.)  Please do not misrepresent my position, 
> especially when I've been fairly consistent on it.
> 
> Also, one of the biggest failings of SPL is the degree to which it leverages 
> and forces extension rather than interfaces.  Inheritance is a code reuse 
> tool, NOT an architecture tool.  That's what interfaces are for.  We know 
> this.  We've been bitten by this.  Building any kind of inheritance-based 
> operator overloading into the language would be a terrible idea.  Let us 
> never speak of it again.


Seems that you have chosen to callout a distinction and take offense to[*] that 
I was never intending. 

When I referenced value objects the *how* was not the important part of my 
discussion but instead that fact that we do get there, evidenced by my use of 
"Or ???" when hypothesizing.

If the way PHP gets there is that a value object is an object where all 
non-private properties are explicitly declared readonly then that is as 
workable as if we explicitly define the class with a "value" keyword. I don't 
really care as I see it as a distinction without a difference. 

Either way if PHP can identify a value object then it could limit operator 
overloads to just classes that are value objects by whatever approach PHP 
chooses to distinguish.


-Mike
[*] Ironically I mentioned you because I thought you would be appreciate seeing 
another reason PHP could benefit from value objects. But as they say, no good 
deeds go unpunished.
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-10 Thread Larry Garfield
On Tue, Aug 10, 2021, at 1:51 AM, Mike Schinkel wrote:

> 2.) Then I thought: What if PHP had the ability to explicitly define 
> *value* objects?  I know this has been something Larry Garfield has 
> mentioned[1] in the past.  
> 
> What if we had a new type of class that is to be used only for value 
> objects. Following Larry's lead they would be immutable. And if we had 
> those then I think adding generic operators overloading to value 
> objects would make a hell of a lot of sense.  Maybe:
> 
> #[\PHP\Value]
> class ComplexNumber{}
> 
> Or:
> 
> class ComplexNumber value{}
> 
> Or:
> 
> ???
> 
> Can you see any reason why only allowing the addition of operator 
> overloads to *value* objects would too limiting? 
> 
> IMO that would minimize the abuse potential for implementing operators 
> as a leaky abstraction when developers are ignorant of the 
> ramifications and/or are more concerning about their convenience than 
> longer term maintainability. 
> 
> [1] https://twitter.com/Crell/status/621715583403487232

Point of order: I do not support a dedicated value-object/data-object 
construct, and have said so explicitly.  I support targeted tools that make 
using objects in that fashion cleaner and more robust.  (readonly, asymmetric 
visibility, clone-with, etc.)  Please do not misrepresent my position, 
especially when I've been fairly consistent on it.


Also, one of the biggest failings of SPL is the degree to which it leverages 
and forces extension rather than interfaces.  Inheritance is a code reuse tool, 
NOT an architecture tool.  That's what interfaces are for.  We know this.  
We've been bitten by this.  Building any kind of inheritance-based operator 
overloading into the language would be a terrible idea.  Let us never speak of 
it again.

--Larry Garfield

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-10 Thread Jordan LeDoux
On Tue, Aug 10, 2021 at 12:15 AM Mike Schinkel  wrote:

>
> So that gives me two (2) thoughts
>
> 1.) First is Geometry would be another area for PHP to consider adding
> classes.
>
> 2.) Then I thought: What if PHP had the ability to explicitly define
> *value* objects?  I know this has been something Larry Garfield has
> mentioned[1] in the past.
>   ...

Can you see any reason why only allowing the addition of operator overloads
> to *value* objects would too limiting?
>
>
Hmmm. My immediate suspicion is that the technical details of how to make
an object that *could* do this would be devilishly difficult. However, as
an alternative to my proposal, it also has a year, so it's something we
should explore. I think that if this were done very, very carefully, it
would cover 80-90% of use cases, so it's worth exploring as part of my
background and research for this RFC.


>
> • Length e.g. meters
> • Time e.g. seconds
> • Amount of substance e.g. moles
> • Electric current e.g. amperes
> • Temperature e.g. kelvin
> • Luminous intensity e.g. candela
> • Mass e.g. kilogram
>
> Those seem like a great *finite* list of fundamental units I would argue
> PHP could benefit userland developers greatly by adding *standardized*
> classes to handle them, maybe in a `PHP\Units` namespace.  We already have
> Time.
>
> Then I can envision a `Value` base class, trait(s) and/or interfaces that
> could support generic unit conversion that these specific units, like
> Length.  1 'm' could be defined equal to 100 'cm' and then this could be
> possible:
>
>
Interesting! So the reason I actually started work on my math library was
to support arbitrary precision math for my units/physics library,
samsara/newton. I haven't updated it in about 8 years so it is... not a
stellar example of the implementation, however handling this behavior is
exactly what my library was for. There are at least two more: plane angle
and solid angle. Plane angle is used in composition of units such as
angular acceleration (plane angle / time^2), while solid angle is used in
composition of the units for illumination (luminous intensity * solid angle
/ length^2).


>
> I'd argue for the shopping cart example it would make it more difficult to
> reason about for the very reason that you gave three different potentials
> for how to define a unit.
>
> As for Length being appropriate for operator overloading, absolutely.
>
>
In a library situation yes, I was more talking in business solutions.
Businesses that run their web application in PHP will build something that
is obtuse to other people, because an individual business is usually obtuse
to people who are not in that business. So I agree that you are correct,
but I don't think there's any preventing that. That's just the nature of
having millions of different programs written in the language IMO.


>
> However, that debate is a digression from our topic so we shouldn't
> further it here.
>
>
Fair.


>
> Unless adding those tools make it less capable at the tasks its best for.
> And I am arguing that adding generic operator overloads for all classes may
> well make PHP less capable for those who want to write robust and reliable
> web applications.
>
> (If we add value object classes and add generic operator overloads there,
> I feel much less concerned about PHP becoming less capable of achieving
> robustness and reliability.)
>
>
Ah, okay. This is the first clear articulation of *what* the issue might
be. Now I will be able to investigate it properly, thank you. :)


>
> One final question.  Let's assume that the functionality in your library
> were to be added to PHP such that your library was no longer needed.  Would
> you be fine with that, or do would you prefer that features added to PHP
> made your library more attractive as opposed to no longer needed?
>
> I'm not suggesting anything untoward — it would be perfectly reasonable
> IMO for you wanting features to enhance your library vs. eliminate the need
> for it — I am just interested to know which avenue you would find most
> compelling?
>
>
I wrote my math library because I found it necessary to support the
units/physics library that I was writing and couldn't find an acceptable
library for it. It was originally a means to an end. The units/physics
library I originally started writing because I wanted to write a web-based
game that people could play, and needed the units library for the kind of
server simulation that I needed to run.

I have actually multiple times considered translating my own math library
to an extension or an RFC. I would have no issue with inclusions to core
making my libraries obsolete. I've been working on them for 11 years and
they are still not finished, it would be honestly amazing if PHP did
support or had supported what I needed to do already.


>
> P.S. I've seen when language features are added that eliminate the need
> for selected domain-specific libraries 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-10 Thread Mike Schinkel
> On Aug 9, 2021, at 8:40 PM, Jordan LeDoux  wrote:
> That is in part of why I asked for use-case examples, to see if there really 
> were a lot of use-cases where operator overloading makes sense.  You only 
> provided two categories; Math and the already existing DateInterval. 
> 
> This seems... a bit reductionist? I suppose if you consider anything that has 
> a numeric value "math", then sure. 

I can see how you might have interpreted my reference to Math as "all math."  

However, I was only referring to the explicit list you provided. Again, for 
reference:

Math

- Complex number objects
- Fractions objects
- Matrix objects (math)
- Vector objects (math)
- Arbitrary precision numbers (which are usually represented as a string in PHP)


> Math is extremely large. Geometry is very different from matrices, which is 
> very different from arithmetic, which is very different from complex numbers.

So that gives me two (2) thoughts

1.) First is Geometry would be another area for PHP to consider adding classes.

2.) Then I thought: What if PHP had the ability to explicitly define *value* 
objects?  I know this has been something Larry Garfield has mentioned[1] in the 
past.  

What if we had a new type of class that is to be used only for value objects. 
Following Larry's lead they would be immutable. And if we had those then I 
think adding generic operators overloading to value objects would make a hell 
of a lot of sense.  Maybe:

#[\PHP\Value]
class ComplexNumber{}

Or:

class ComplexNumber value{}

Or:

???

Can you see any reason why only allowing the addition of operator overloads to 
*value* objects would too limiting? 

IMO that would minimize the abuse potential for implementing operators as a 
leaky abstraction when developers are ignorant of the ramifications and/or are 
more concerning about their convenience than longer term maintainability. 

[1] https://twitter.com/Crell/status/621715583403487232

> Again, I'm providing those examples because I can literally bring up code 
> from my own libraries for those, so I'm a good advocate for them. But others 
> certainly exist. I think you would throw this under "math", but what about 
> unit-based values? If you wanted to do `19cm + 2m`, you could return `219cm`, 
> or `2.19m`, or `2190mm`. Supposing that there was an abstract, how would it 
> know what unit conversion to use? Or what about `2km + 4mi`? Or what about 
> erroring for `2km + 4L`?

Length is a really great example, thanks for bringing it up.  

According to NIST there are seven (7) base units[2] where "Definitions of all 
seven (7) SI base units are expressed using an explicit-constant formulation 
and experimentally realized using a specific mises en pratique (practical 
technique)."  

This means they are well-known and unlikely have changing requirements. They 
are:

• Length e.g. meters
• Time e.g. seconds
• Amount of substance e.g. moles
• Electric current e.g. amperes
• Temperature e.g. kelvin
• Luminous intensity e.g. candela
• Mass e.g. kilogram

Those seem like a great *finite* list of fundamental units I would argue PHP 
could benefit userland developers greatly by adding *standardized* classes to 
handle them, maybe in a `PHP\Units` namespace.  We already have Time.

Then I can envision a `Value` base class, trait(s) and/or interfaces that could 
support generic unit conversion that these specific units, like Length.  1 'm' 
could be defined equal to 100 'cm' and then this could be possible:

use PHP\Units\Length;
$length = (new Length(19,'cm')) + (new Length(2,'m'));
echo $length->toCentimeters(); // prints 219
echo $length->toMeters(); // prints 2.19 
echo $length->toMillimeters();   // prints 2190

$length = (new Length(2,'km')) + (new Length(4,'mi'));
echo $length->toMiles();  // prints 5.24274
echo $length->toKilometers(); // prints 8.43736

Then something like this could also be valid, and be what the above is actually 
built on:

use PHP\Units\Units;
use PHP\Units\Value;
$units = new Units();
$units->addUnit('m','Meter');
$units->addUnit('cm','Centimeter');
$units->addUnit('mm', 'Millimeters');
$units->addConversion('cm','m',100);
$units->addConversion('mm','m',1000);
$length = (new Value(19,'cm',$units)) + (new Value(2,'m',$units));
echo $length->toUnit('cm');// prints 219
echo $length->toUnit('m');  // prints 2.19 
echo $length->toUnit('mm');   // prints 2190

$units->addConversion('m','km',1000);
$units->addConversion('mi','km',1.60934);
$units->addUnit('km', 'Kilometers');
$units->addUnit('mi','Miles');
$length = (new Length(2,'km',$units)) + (new Length(4,'mi',$units));
echo $length->toUnit('km');// prints 5.24274
echo $length->toUnit('mi'); // prints 8.43736

We could even open up the discussion of having scalar literals for these types, 
e.g. where `2m` is a 2 meter  value object of type Length.

Note that having value objects and having these seven 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-09 Thread Jordan LeDoux
On Mon, Aug 9, 2021 at 2:32 PM Mike Schinkel  wrote:

> However, you are actually making my point, which is that since they are so
> deterministic then why is there the need for flexibility to be done in
> userland vs. the standardization that could be could be better in PHP core?
> For the latter we can ensure the abstractions are not leaky and the
> requirements are fully addressed.
>
>
They are deterministic for given *values* and *types*. They are not
deterministic over the whole category.


>
> Why don't we start with this?  Rather than initially focus on the syntax
> for creating operator overloading why don't we start by focusing on the
> known use-cases and come up with documentation showing how those use-cases
> would leverage the custom operators?  Fully map them out.
>
> If we do that and we still get general operator overloading then at least
> userland will have a roadmap for how to get started with operator
> overloading for the known use-cases rather than lots of developers seeing a
> shiny new feature that they all start adding to their code, badly.
>
> You can easily create this doc on GitHub and solicit PRs from others far
> and wide for their use-cases.
>
>
I have the stub RFC on github:
https://github.com/JordanRL/operator-overloading-rfc

However your suggestion is an excellent one. I will add some interfaces and
abstract classes to that repository when I am able to illustrate what user
implementations (or the PHP expressions of the C implementations) might
look like.


>
> It would help me if we could discuss this in specific terms rather than
> abstract terms.  What does "fully-featured complex number library" mean?
> Can you create a Gist showing what the class interfaces would look like in
> PHP code?
>
>
I mean that it would need to be a complex number literal or object that
fully understood its relationship to other literals and to the operators.
The interfaces, if you ignore typing, would be similar to other number
classes, but the *implementations* would be very different. That's the
biggest problem with providing say a single abstract number class that has
built in operator overloading. Unless it can then be extended and
overridden, in which case it seems that it will result in much more heinous
misusage to me than simply doing generic operator overloading.


>
> Correct me as I may be wrong, but isn't int+imaginary a function of (r,
> theta) and vice-versa?
>
> If yes, I assume that both representations could be generated by the same
> ComplexNumber class?
>
>
Yes you're correct. The values of both representations are computed when
changed in my own ComplexNumber class, and the most advantageous one in
terms of algorithmic complexity is used for calculation in any given method.


>
> The custom operator overloads in C require a lot more skill and experience
> to implement than in PHP which I am arguing is a benefit related to
> operator overloading.
>
> Further, only people who are not using managed hosting that constrains the
> extensions used are able to use these extensions.  So these overloaded
> operators are not infecting PHP code far and wide.
>
>
The overloaded operators don't interfere with anything *at all* unless you
use an object that has them defined, even if you use the extensions. The
GMP operator overloads don't affect anyone unless they are using GMP. These
will be the same, in that the operators are unaffected unless a class opts
in to using the feature.


>
> We have differing opinions on that, so we should agree to disagree on that
> subjective assessment.
>
>
Alright.


> stdClass objects also support equals comparison so really this is more
> about add, subtract operators which DateTime and TimeInterval do not have.
>
> Which brings up this question: If we allow comparison operator overloading
> for objects does that DateTime comparisons might no longer mean they are
> the same pointer but instead a userland comparison?  If yes, that actually
> chills me to the bone.
>
> https://3v4l.org/2RCot#v8.0.9
>
>
The identity comparisons (`===` and `!==`) were two comparisons that I
specifically planned to exclude from this RFC.


>
> That's absolutely fine and understood. That's the way it works for PHP.
>
> Similarly I will advocate others consider fleshing out specific use-cases
> and ideally have us implement a few before we consider adding generic
> operator overloading to PHP.
>
> Unless of course I find that there is a strong consensus to move forward
> with generic operator overloading in which case I will demure.  But thus
> far it is not clear which way that wind actually blows.
>
>
And I wouldn't expect it to be clear at this point. I was reaching out now
more to gather a list of preferences and concerns for the feature. Perhaps
the best way to think about what I was looking for was the answers to these
questions:

1. If anyone planned to vote against such an RFC regardless of
implementation, details, or need, why? Could I understand what those

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-09 Thread Jordan LeDoux
 Apologies, this is being broken into two messages because of the 3
byte limit on the list.

On Mon, Aug 9, 2021 at 2:32 PM Mike Schinkel  wrote:

>
> Improving documentation is an easier fix than adding a complex language
> feature. And a key difference is (almost?) anyone who is motivated can
> contribute to the docs; not so for adding language features.
>
> For example, why is it not an option for you to update the docs for
> DateTime and DateInterval if the docs are bad? Or other classes that have
> could have operator overloading in the future?
>
>
Oh absolutely. That's definitely worth doing and likely something that I
will contribute to over time, but it's not really the focus of this effort.


> So are you arguing that PHP should have no library functionality and have
> everything implemented in PHP?
>
> I don't mean to commit a reductio ad absurdum, but I am honestly confused
> by your need to see the implementation of behavior in PHP that is
> well-known and well-established in science and business.
>
>
No, it isn't a need. My point wasn't that documented library functions are
totally inadequate, it was that for incredibly specific things it is often
more useful to be able to consult your own codebase. Documentation is
great, and what I'm saying isn't that core implementations are bad because
then people need to consult the documentation. I was giving one of several
small reasons that I would prefer *this* feature inside a codebase if I
were deciding, and self-documenting code was just one of them. I'm sorry if
I gave the impression that the library or core features are less acceptable.

Anything that uses operator overloading will do so in a domain specific
way, that's the point of the feature. So to me, it makes more sense to
contain it in the same codebase if I'm given the option. That's all I'm
saying.


>
> Why it will be important to see operator overloading implementations in
> PHP when you don't see sin() and cos(), for example?
>
> This really feels like a personal preference and not a driving need for
> everyone. But if others agree that seeing operator overloading in PHP code
> is critical, please do speak up and, for my edification, please do explain
> why.
>
>
Funny story, I actually *did* need to consult the implementations for sin()
and cos(), but that was highly unusual and due to the specifics of the
library I was working on. My desire to see the operator overrides in user
code *is* a preference. Most things are in programming... I mean, Conway's
Game of Life is Turing complete, you could theoretically write a PHP
interpreter in *that*. And I don't say that to suggest that my feature
proposal is equally as important or simple as other things already in the
language, just that this isn't about the feature being critical (though in
some ways it is for particular domains), rather I am trying to *improve*
the language. This isn't an oversight or missing element from the language
I'm trying to patch, I'm just trying to make an earnest effort at something
that I believe will make the language better than it currently is. And
that's something that is inherently subjective I believe.


>
> Yeah, I don't see this as a problem.  Internally if there are a lot of
> similarities than the similarities can be shared by a common function.
>
> Duplication is not a problem in an of itself. If you only have to write it
> once and rarely ever need to maintain it.
>
>
Perhaps. Personally (and this is also something that is definitely a
preference), I find it a little unseemly to imagine DSL abstracts for a
random assortment of domains in the language. It gets the job done, it
doesn't require constant maintenance as you point out. I simply... find it
to be a lackluster result. I'll think about this at more length to see if I
can concretely describe why.


>
> That is in part of why I asked for use-case examples, to see if there
> really were a lot of use-cases where operator overloading makes sense.  You
> only provided two categories; Math and the already existing DateInterval.
>
>
This seems... a bit reductionist? I suppose if you consider anything that
has a numeric value "math", then sure.

Math is extremely large. Geometry is very different from matrices, which is
very different from arithmetic, which is very different from complex
numbers.

Again, I'm providing those examples because I can literally bring up code
from my own libraries for those, so I'm a good advocate for them. But
others certainly exist. I think you would throw this under "math", but what
about unit-based values? If you wanted to do `19cm + 2m`, you could return
`219cm`, or `2.19m`, or `2190mm`. Supposing that there was an abstract, how
would it know what unit conversion to use? Or what about `2km + 4mi`? Or
what about erroring for `2km + 4L`?

These are *certainly* more common in general PHP applications than my own
math library examples.

Another good example of unit based values would be online stores
controlling 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-09 Thread Mike Schinkel
On Aug 9, 2021, at 5:32 PM, Mike Schinkel  wrote:

> On Aug 9, 2021, at 1:48 PM, Jordan LeDoux  wrote:
> You claim that this would be documented on php.net and this would be 
> sufficient. Yet the DateTime class has had operator overloads for comparison 
> operators since 5.2 and there is still *zero* mention on php.net (that I am 
> aware of or can find) of this. Not even a mention that it exists, let alone 
> what the override behavior is. *Not even in the god-awful comments on the 
> manual.*

Improving documentation is an easier fix than adding a complex language 
feature. And a key difference is (almost?) anyone who is motivated can 
contribute to the docs; not so for adding language features. 

For example, why is it not an option for you to update the docs for DateTime 
and DateInterval if the docs are bad? Or other classes that have could have 
operator overloading in the future?

> Simply put, as someone who has spent my entire career working primarily in 
> PHP and been working in it since PHP 4, it has one of the very best free and 
> online manuals for any language I've worked in, and I would still 10 times 
> out of 10 prefer to be able to see the implementation in my IDE than have to 
> look it up on php.net.

So are you arguing that PHP should have no library functionality and have 
everything implemented in PHP? 

I don't mean to commit a reductio ad absurdum, but I am honestly confused by 
your need to see the implementation of behavior in PHP that is well-known and 
well-established in science and business.  

I honestly don't get why it would be important to see the internals of DateTime 
and DateInterval class, or a ComplexNumber or a Money class for that matter. 
Why can't that just be documented, other than your claim that "docs are bad?"  

Why it will be important to see operator overloading implementations in PHP 
when you don't see sin() and cos(), for example?

This really feels like a personal preference and not a driving need for 
everyone. But if others agree that seeing operator overloading in PHP code is 
critical, please do speak up and, for my edification, please do explain why.

>  What I mean is that there would be multiple "number like" abstract classes 
> that would be 80% to 90% similar. That is, if it actually correctly 
> represented the core math ideas. This method however would utterly fail for 
> unit based value overloads, of which Rowan's money example is a specific case.

Yeah, I don't see this as a problem.  Internally if there are a lot of 
similarities than the similarities can be shared by a common function. 

Duplication is not a problem in an of itself. If you only have to write it once 
and rarely ever need to maintain it.

> However, creating abstract classes simply for custom operator overloads would 
> signal to users that this is something internals is willing to do. Despite 
> the fact that I am confident the process would continue to work, I would very 
> much anticipate multiple and continuous threads opened by users wondering 
> when "their" operator overloads are going to be included. While this 
> obviously doesn't force anything, it absolutely is a distraction.

That is in part of why I asked for use-case examples, to see if there really 
were a lot of use-cases where operator overloading makes sense.  You only 
provided two categories; Math and the already existing DateInterval. 

It's not like operator overloading is a feature which without developers 
literally cannot implement functionality. Even though you (currently) cannot 
compose an expression of objects like `$cn1 + $cn2` doesn't keep you from 
implementing `$cn1.add($cn2)`.

Let us assume that because we were to create operator overloads for DateTime 
and DateInterval and for your Math needs people started inundating the list 
with requests to add hundreds of other classes (I really doubt that would 
happen, but I'm running with it anyway.) 

One easy answer is for the list to come up with a checklist for operator 
overloading concerns and request those asking to present userland libraries 
that would want operator overloading and show how the libraries would address 
the concerns in the checklist. Once done, then the list could review and make a 
decision.

OR, *if* the list really is inundated with requests, maybe we *then* realize 
there are many use-cases, and we move towards a generic operator overloading.  

But as of today I am not convinced that there are really that many use-cases 
for operator overloading that would not just be a leaky abstraction.

(As an aside, how are we going to implement operator overloading in DateTime 
and DateInterval within PHP?  Do we have to subclass just to get them to have 
operators?  So minimally, we should start with those two and write it in C for 
PHP core.)

>> https://medium.com/@rwxrob/operator-overloading-is-evil-8052a8ae6c3a
> I was hoping for something more concrete than what he said in this article, 
> especially when the one and 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-09 Thread Jordan LeDoux
On Mon, Aug 9, 2021 at 11:40 AM Peter Cowburn  wrote:

> On Mon, 9 Aug 2021 at 18:48, Jordan LeDoux 
> wrote:
>
>>
>> You claim that this would be documented on php.net and this would be
>> sufficient. Yet the DateTime class has had operator overloads for
>> comparison operators since 5.2 and there is still *zero* mention on
>> php.net
>> (that I am aware of or can find) of this. Not even a mention that it
>> exists, let alone what the override behavior is. *Not even in the
>> god-awful
>> comments on the manual.*
>>
>
> For future reference: https://www.php.net/manual/en/datetime.diff.php
>

Thank you. I honestly did look for it quite extensively.


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-09 Thread Peter Cowburn
On Mon, 9 Aug 2021 at 18:48, Jordan LeDoux  wrote:

>
> You claim that this would be documented on php.net and this would be
> sufficient. Yet the DateTime class has had operator overloads for
> comparison operators since 5.2 and there is still *zero* mention on
> php.net
> (that I am aware of or can find) of this. Not even a mention that it
> exists, let alone what the override behavior is. *Not even in the god-awful
> comments on the manual.*
>

For future reference: https://www.php.net/manual/en/datetime.diff.php


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-09 Thread Jordan LeDoux
On Mon, Aug 9, 2021 at 3:49 AM Mike Schinkel  wrote:

> 1. When you speak of "not documented in the code" do you mean the
> implementation would not be in PHP code? Okay, yet none of these functions
> are documented in PHP code and they are all available in PHP:
>
> https://www.php.net/manual/en/ref.math.php
>
> AFAIK few people who do not struggle with programming or math have any
> problem with these functions, because they are all documented.
>

Yes, that is precisely what I mean. Operator overloading is a complex
feature, I have never pretended otherwise. Having the behavior documented
in the code base you are working on, in the code itself, is FAR more
useful. My primary example of that is this:

You claim that this would be documented on php.net and this would be
sufficient. Yet the DateTime class has had operator overloads for
comparison operators since 5.2 and there is still *zero* mention on php.net
(that I am aware of or can find) of this. Not even a mention that it
exists, let alone what the override behavior is. *Not even in the god-awful
comments on the manual.*

Simply put, as someone who has spent my entire career working primarily in
PHP and been working in it since PHP 4, it has one of the very best free
and online manuals for any language I've worked in, and I would still 10
times out of 10 prefer to be able to see the implementation in my IDE than
have to look it up on php.net.


> 2. Yes, it would require many different implementations, one for each
> use-case. Unique logic has to be implemented. Somebody has to do it. Why is
> that a problem?
>
> I am not sure what you mean by being "very close to each other to cover
> the same set of use-cases" unless you are talking about many different
> arbitrarily different userland implementations, which I doubt since that
> would be a reason not do add operator overloading.
>
>
What I mean is that there would be multiple "number like" abstract classes
that would be 80% to 90% similar. That is, if it actually correctly
represented the core math ideas. This method however would utterly fail for
unit based value overloads, of which Rowan's money example is a specific
case.


> 3. Regarding maintainability concerns. Code generally doesn't rot unless
> the requirements change. Are requirements going to change? If yes, then its
> not a strong use-case for operator overloading, in core or userland. We
> should guard against operators used for convenience that are leaky
> abstractions.
>
> BTW nobody can "demand" new features in PHP and be effective. But if they
> propose them in an RFC it helps ensure these new features are fully fleshed
> out, to the best of the list's collective ability.
>
>
Yes, I'm aware. :) The process that PHP employs with internals to maintain
the language is one of its greatest strengths in my personal opinion. I
shouldn't be able to simply open a PR and have the maintainer be the only
one that looks at it. My RFC, whether it is accepted or not, will be better
because of this process. It has already been improved by this thread.

However, creating abstract classes simply for custom operator overloads
would signal to users that this is something internals is willing to do.
Despite the fact that I am confident the process would continue to work, I
would very much anticipate multiple and continuous threads opened by users
wondering when "their" operator overloads are going to be included. While
this obviously doesn't force anything, it absolutely is a distraction.


> While it is hard to objectively quantify how much is "much" this gentlemen
> — a programming teacher — had some choice words to say about operator
> overloading specifically related to Python:
>
> https://medium.com/@rwxrob/operator-overloading-is-evil-8052a8ae6c3a
>
> A pull quote from his blog post:
>
> "You wanna know what is not simple? Operator overloading. It has no place
> in any language. It’s an aberration to be shunned."
>
> He feels even more strongly about the perils of userland operator
> overloading than I do!
>

:/

I was hoping for something more concrete than what he said in this article,
especially when the one and only comment on the article succinctly
expresses why it's incorrect. Python's major "selling point" over other
languages, especially for its initial adoption and wide use in teaching, is
its power in scientific computing, and those libraries 100% *depend* on
Python's operator overloading.


> A while back someone proposed __ToArray and Rowan (among others) fought
> back hard saying that the problem is that exporting an object to array
> could mean different things to different people and there is often a need
> to export to multiple different array format, and thus the use-case should
> always be implemented as a named function.  A first I was annoyed that the
> list was pushing back because I wanted to use __ToArray, but the more I
> thought about it the more I realized that Rowan and others were right.
>
> Overloaded operators are no 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-09 Thread Mike Schinkel
> On Aug 8, 2021, at 3:41 AM, Jordan LeDoux  wrote:
> 
> Off the top of my head here are some of the use cases that I think benefit 
> greatly from this:
> 
> - Complex number objects
> - Fractions objects
> - Matrix objects (math)
> - Vector objects (math)
> - Time/Date intervals
> - Collections
> - Arbitrary precision numbers (which are usually represented as a string in 
> PHP)

Thank you for going to the effort to list those out.  I'd like to categorize 
them, if I may?


General Purpose
- Collections

I'm not sure if you there is something about Collections related to Math that 
makes them applicable for operator overloading but otherwise I would be 
question whether there would be a strong consensus around what operators a 
collection would implement and how those operators would behave.  

If you think there would be a strong consensus regarding collections and 
operators maybe you could elaborate on which operators would apply and what 
each would do?


Date/Time
- Time/Date intervals

This seems to me to be a great use-case. Ironically we already have the 
DateInterval class as well as methods that operate on DateTime objects that add 
and subtract DateIntervals as well as proving the different between two dates.

Because we already have the classes, this seems to be a perfect place to start 
with an RFC to introduce operators to PHP for DateTime and DateInterval 
objects.  

More on this in a bit.


Math
- Complex number objects
- Fractions objects
- Matrix objects (math)
- Vector objects (math)
- Arbitrary precision numbers (which are usually represented as a string in PHP)

And these all seem like strong candidates for classes that could use operators. 
 

But mathematical concepts are pretty well set in stone; are there really this 
many different ways to implement them (rhetorical question)?:

> Here are some actual user libraries which would probably use them:
> 
> - samsara/fermat (this library is mine as a matter of disclosure)
> - brick/math
> - markbaker/complex
> - markbaker/matrix
> - krowinski/bcmath-extended
> - malenki/math
> - markrogoyski/math-php
> - rubix/tensor
> - numphp/numphp
> - mcordingley/linear-algebra

Looking at the tests for just complex numbers in just three (3) of these I see 
distinctly different choices, choices which appear to be arbitrarily made by 
each developer:

1. 
https://github.com/SamsaraLabs/FermatComplexNumbers/blob/master/tests/Samsara/Fermat/Values/ImmutableComplexNumberTest.php
2. 
https://github.com/MarkBaker/PHPComplex/blob/3.0/unitTests/classes/src/ComplexOperationTest.php
3. https://github.com/malenkiki/math/blob/master/tests/Number/ComplexTest.php

I really can't critique the math aspects nor fully grok your use-cases, but do 
I understand the benefit of standardization, and it seems like PHP would gain 
greatly for use in the math domain by introducing classes written in C and 
baked into core for each of your math use-cases.

And the same with the Money classes that Rowan proposed.

But I know you objected to that approachmore on that at the end.

> As for constraints... well, if I had absolutely no concern for implementation 
> at all, and was just designing what constraints to put on the magic methods, 
> they would be:

> 1. void is an unsupported return, and failing to return a value results in an 
> error.
> 2. Variables outside the scope of the method cannot be set. This includes 
> properties on the object which is defining the magic method, and includes 
> sets that occur in called functions and methods.

When I mentioned "constrained" I was referring to Rowan's distinction:

> On Aug 7, 2021, at 3:07 PM, Rowan Tommins  wrote:
> In a previous thread [1], I wrote about two fundamental design approaches to 
> operator overloading:
> 
> a) Treating operators as arbitrary symbols, which can be assigned any 
> operation which makes sense in a particular domain.
> b) Treating operators as having a fixed meaning, and allowing custom types to 
> implement them with that meaning.

Where a) would be "unconstrained" and b) would be "constrained."  I think you 
assumed I was referring to something else.

> In any case, it is certainly possible that we could instead implement some 
> magic *objects* which can be extended that have built-in overloading in 
> specific ways. I think this is actually worse for the following reasons:
> 
> 1. It would be far less obvious to the programmer that an object would behave 
> differently with a given operator, because the behavior wouldn't be 
> documented in the code itself.
> 2. It would require many different implementations, some of them very close 
> to each other, to cover the same set of use cases.
> 3. It would likely result in some maintainability concerns as more users 
> demanded different DSL type implementations be included in core, and the 
> existing ones would need to be maintained.

I am going to challenge your 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Jordan LeDoux
On Sun, Aug 8, 2021 at 9:52 AM Rowan Tommins 
wrote:

>
> Yes, and as I demonstrated, there are situations where some of the
> operators are only meaningful for a subset of operands. Saying that a
> Money object is "Multipliable" would also be "a lie", since multiplying
> two Money objects together is a logic error, even though multiplying
> Money by a unit-less number is very useful.
>
>
This is a good point, and your example of currency was a great example of a
whole class of other things that would benefit: unit based values.

I've started to work on the RFC document to collect some of the information
we've discussed in this thread. I do not have the ability to edit
wiki.php.net, so I cannot put the RFC on there at the moment. In lieu of
that, I've created a placeholder markdown document on github for the RFC
page:

https://github.com/JordanRL/operator-overloading-rfc/

This is not where I will work on the implementation (which will obviously
be on a fork of php-src). I've outlined my rough idea of the implementation
I'm leaning towards in this doc, but have left out any discussion about
interfaces for now, as I feel that's something that could use further
discussion. Any feedback would be appreciated at this early stage.

Jordan


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Rowan Tommins

On 08/08/2021 16:39, Larry Garfield wrote:

1) Implementing an interface and stubbing out some methods is a lie. It's a lie 
the engine won't stop you from telling, but it's still a lie.  If you only 
support addition and division, for instance (add to a collection and split a 
collection into several), then having a bunch of comparison methods that your 
object says you support but the program dies as soon as you use it is a lie, 
and a landmine waiting to happen.



I find it odd, given your other comments, that you keep coming back to 
collection examples, which seem to me very much in the realm of 
re-defining the symbols to mean something different in a new domain. If 
"+" can mean "union" and "/" mean "partition", why not also let "<<" 
mean "append"?


If we're saying we don't want "arbitrary weirdness", then discouraging 
"add" and "divide" on a collection feels like a feature, not a bug.




2) As Jordan demonstrated, there are many even formally defined situations 
where some of the operators are explicitly meaningless.



Yes, and as I demonstrated, there are situations where some of the 
operators are only meaningful for a subset of operands. Saying that a 
Money object is "Multipliable" would also be "a lie", since multiplying 
two Money objects together is a logic error, even though multiplying 
Money by a unit-less number is very useful.



Regards,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Larry Garfield
Responding to a bunch of people at once here, for simplicity:

On Sat, Aug 7, 2021, at 7:04 PM, Jordan LeDoux wrote:


> > The 4 arithmetic operators, concat, and compare.
> 
> I would argue that both modulo and pow (% and **) are arithmetic operators
> that should come with the basic four as well. Meanwhile, I think the concat
> operator is both more prone to error *and* less useful. Currently, if you
> try to concat an object, it will be cast to a string, and since
> __toString() already exists, this behavior can effectively be controlled
> already. The main reason that other operators couldn't easily be solved
> with supplementary __to*() methods is that for *many* usecases where you'd
> benefit from overloading operators, the scalar types don't adequately
> capture the state (which is presumably the reason that the program is
> representing them as objects).

Fair point on concat.  I am not sure that mod and pow are logical, except for 
completeness purposes.  Either way, the general point is that we can and should 
start with a smaller set of operators to prove the concept, then expand it in 
additional RFCs.  (Assuming that the pattern would be effectively the same for 
any operator once the plumbing is in place.)

> Further, as detailed in my earlier reply, I don't think we can get away
> with only allowing compare. Complex numbers are a trivial example of why,
> but there are many others where only some of the comparison operators make
> sense. We could, however, allow compare as a minimal implementation to
> support the others. If it is implemented, then the others can be derived,
> but if it is not then the other comparison operators should be able to be
> implemented individually.

Hrm.  Having two different versions of comparable feels highly problematic to 
me, just from an understandablity point of view.  We would have to try and 
figure out which if any combinations necessarily really do have to come 
together (eg, is implementing < but not > even possible?).  I don't think 
there's a way to implement one of two mutually exclusive interfaces.  I'd hate 
to push comparables to their own RFC as that's also been its own ball of 
controversy in the past, but...


> As such, I think the idea of operator overloading is fundamentally
> incompatible with the concern of ensuring commutability. In fact, *many* of
> the usecases for this feature would *depend* on them not being commutable.
> For matrices, A * B != B * A except under specific values. This is in fact
> part of the definition of multiplication under matrices, so I feel that
> wanting to ensure commutative behavior actually represents misunderstanding
> the feature itself. Extending the native operators to work with matrices
> using an internal implementation would *also* result in non-commutative
> behavior, because that's the *correct* behavior for matrices.

A good point.  I would urge you to include the Matrix example in the RFC to 
head off any complaints about commutability.

> As such I think that requiring static methods is a way to make internals
> "feel better" about it without actually providing any real guarantees of
> consistency or immutability.

I concur.

> > What if any type enforcement should the language force?
> 
> Personally I do not think that any type enforcement should be required. I
> think it should be *possible* if the application wants it, but I don't
> think it should be required.

So, that's essentially the __invoke() approach I suggested.  I'm good with that.


On Sun, Aug 8, 2021, at 2:41 AM, Jordan LeDoux wrote:

> In any case, it is certainly possible that we could instead implement some
> magic *objects* which can be extended that have built-in overloading in
> specific ways. I think this is actually worse for the following reasons:

An abstract base class-based implementation is an instant-no from me, full 
stop.  Let's not and say we didn't.

On Sun, Aug 8, 2021, at 6:25 AM, Jordan LeDoux wrote:

> So while I'm aware of the concerns, I'm unconvinced they are founded in
> reality. That is, I think the concerns about maintainability and complexity
> may be unfounded in real world scenarios. However it is an extremely
> consistent opinion here, and I would like to understand *why* it is viewed
> as bad for the language in a more concrete way if that is possible.

I can't speak for Ruby, but I suspect at least part of it is is C++.  I have 
heard plenty of complaints about C++'s overloading implementation, which allows 
all kinds of arbitrary weridness.  That's why I was arguing previously for a 
more named approach, as that provides a more Python-esque suggestion of how to 
use a given overload properly.

Adopting Python's r*OP naming to handle rhs overloads is interesting, but I'm 
not sure I like it.  It feels like it may just be begging for more complexity 
and weird behavior.  But I'm open to further investigation of it.

On Sun, Aug 8, 2021, at 8:11 AM, Rowan Tommins wrote:

> Since even a single 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Rowan Tommins

On 08/08/2021 08:41, Jordan LeDoux wrote:

Off the top of my head here are some of the use cases that I think benefit
greatly from this:

- Complex number objects
- Fractions objects
- Matrix objects (math)
- Vector objects (math)
- Time/Date intervals
- Collections
- Arbitrary precision numbers (which are usually represented as a string in
PHP)



I think that although mathematical libraries feel like a natural 
example, they're actually rather a small niche in the world of PHP, so 
not a great advert for the feature. Collections are not necessarily a 
great example either, since defining "+" to mean "combine these two 
collections in some type-specific way" is the kind of broad overloading 
which is often controversial.


An example which I think would be applicable to many more PHP users is a 
"Money" type, with a value, a currency, and perhaps a precision. It's 
also an interesting example where all the mathematical operators can be 
implemented, but restricted to certain combinations of types, and even 
combinations of values.


A real-life example from a C# project has the following overloads 
(syntax tweaked to be more PHP-like):


public static operator - (Money $m1, Money $m2): Money
public static operator + (Money $m1, Money $m2): Money
public static operator / (Money $money, float $divisor): Money // 
fraction of a Money value
public static operator / (Money $m1, Money $m2): float // ratio of two 
Money values
public static operator * (Money $money, float $multiple): Money // note 
[Money * Money] is not defined

public static operator < (Money $m1, Money $m2): bool
public static operator > (Money $m1, Money $m2): bool
public static operator == (Money $m1, Money $m2): bool
public static operator != (Money $m1, Money $m2): bool // defined as 
!($m1 == $m2)


All operators which take two Money values throw an exception if they 
have different currencies.


The [float * Money] case isn't overloaded here, although it would make 
sense; I don't know if that's because it can't be in C#'s overload 
system, or just that it is missing from this implementation.


Since even a single operator interface can't guarantee that all inputs 
will have a valid output, I remain unconvinced that implementing 8 
different interfaces for the above is any better than implementing one 
interface and stubbing the parts that have no valid inputs.


Regards,

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Jordan LeDoux
On Sun, Aug 8, 2021 at 3:08 AM Deleu  wrote:

> I started reading this thread with a total bias against it and as I read
> through it I can only imagine how painful and annoying it is to maintain a
> math library in PHP. Operator Overloading is truly a marvelous piece of
> functionality for that domain.
>
> However my biased still exists: it would be awful to have to understand
> what `+` is doing for every file of every library or even different objects
> in the same project.
>

May I ask why? Python does not get much criticism that I can find for its
implementation of operator overloading. Its implementation of operator
overloading is very widely used in the language and is also not seen as a
major source of "suck" for lack of a better term. Python allows virtually
all operators to be overloaded, and takes the unique approach of having an
add() method for when the object is on the left and radd() for when the
object is on the right, with precedence always going to the leftmost object.

There are many languages that provide operator overloading, and I've never
seen it described as a bad feature in any of them. I've seen criticisms of
the particular way it was implemented in a few, but not for the feature
itself. I obviously understand the possible problems that could come from
it. I work in PHP every day at work on a codebase that was originally
written 11 years ago and has been maintained, updated, and added to. We run
it on 7.4 now, and every year we have all the devs in the company spend
time on migrating to the next PHP version. In such a codebase, I'm well
aware of what kind of problems I *might* have encountered with operator
overloading.

But these don't seem to be major sources of problems in most other
languages.

Python even has multiple *default* overloads.

# prints 12
print(4 * 3)

# prints PythonPythonPython
print("Python" * 3)

So while I'm aware of the concerns, I'm unconvinced they are founded in
reality. That is, I think the concerns about maintainability and complexity
may be unfounded in real world scenarios. However it is an extremely
consistent opinion here, and I would like to understand *why* it is viewed
as bad for the language in a more concrete way if that is possible.

> It's been nearly a decade since I part ways with Math, but if I'm not
mistaken we can tackle most (all?) of the operator overloading with 2
classes: Number and NumberCollection (for lack of genetics).

> Everything in math can programmatically be represented as these two
*abstract* classes.

This would very heavily depend on how broad they were. For instance, while
complex numbers and fractions are both numbers, they would not implement
all of the same operator overrides most likely. I think this is a workable
solution, in that it would give the core feature in a way that can be
muddled through to math-domain applications. However, I won't be doing that
in my RFC. Not so much because I think it is an untennable solution for
math (although it would indeed be FAR more complex of a solution from an
RFC standpoint that directly allowing operator overrides). Instead, the
reason that I won't be doing that in my RFC is that I would no longer want
it to be accepted.

If I wrote that in my RFC just to get the overrides that benefited the work
I do, primarily around math, accepted into core, it would virtually
guarantee that actual operator overrides would never come for other types
of applications. Every future RFC on this topic would be riddled with
comments about the existing abstract classes, and how all future
implementations have to be done in a similar way. This would artificially
increase the barrier to acceptance for other domains in a way that I do not
believe improves the language, serves the users of the language, or allows
for flexible development of the language into the future.

So while I acknowledge that it may be a good middle ground (and even one
that I personally would accept for my own implementations and code), I am
unwilling to be the person that locks everyone *else* out of this language
feature by making future RFCs more constrained and difficult to pass.

I constrained this RFC to math operators not because it's the only domain
that would benefit, but because I think it's the one with the most
straightforward and understandable domain uses for everyone on this list
and represents the "minimum" version of the feature.

Jordan


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Deleu
I started reading this thread with a total bias against it and as I read
through it I can only imagine how painful and annoying it is to maintain a
math library in PHP. Operator Overloading is truly a marvelous piece of
functionality for that domain.

However my biased still exists: it would be awful to have to understand
what `+` is doing for every file of every library or even different objects
in the same project.



> > Ruby has operator overloading, and one of the distasteful aspects I found
> > regarding in programming in Ruby was that everybody's Ruby code you
> looked
> > at felt like I was written in a slightly different language. I would hate
> > that to become the case with PHP, more than it already is.
>

+1


> > 2.) Would it possible that instead of adding operator overloading we
> could
> > add classes that could be extended where PHP actually defines the
> operators
> > for those classes?
>

+1.


> In any case, it is certainly possible that we could instead implement some
> magic *objects* which can be extended that have built-in overloading in
> specific ways. I think this is actually worse for the following reasons:
>
> 1. It would be far less obvious to the programmer that an object would
> behave differently with a given operator, because the behavior wouldn't be
> documented in the code itself.
>

For my vision, this point doesn't make sense. After reading my reply if
this still holds true please extend upon it if possible.

3. It would likely result in some maintainability concerns as more users
> demanded different DSL type implementations be included in core, and the
> existing ones would need to be maintained.
>

True, but I see this as a good thing. The bar to bring something into core
is so high that this is a protective layer against overdoing it.


> As I've mentioned, while I understand that to many programmers
> commutativity is a requirement of a good language, it is explicitly
> incorrect to require commutativity for math operations. The arithmetic
> operators are commutative for the real numbers, but there are many valid
> math concepts for which they are not commutative, and I feel like pushing
> for commutativity is a mistake. It is an attempt to force a behavior that
> we want on code that it may be incorrect for.
>

Totally with you here.


It's been nearly a decade since I part ways with Math, but if I'm not
mistaken we can tackle most (all?) of the operator overloading with 2
classes: Number and NumberCollection (for lack of genetics).

Everything in math can programmatically be represented as these two
*abstract* classes.

Number:
0
1
27
-30
14 + i
f(x)
7/0 (joking!)
10!
15/8
3.141592...
0.9...
45°
|-10|
log(n)


NumberCollection
Matrices
Sets
Expression


We have precedence for this: Datetime objects provided by PHP have operator
overloading. However it might be best for PHP to steer away from the
implementation and provide the abstract classes so that userland implements
them. These classes would allow operator overloading and if possible maybe
even a small hint of method overloading?

```
public function __add(Number $number): Number|NumberCollection
{

}

public function __add(NumberCollection $number): Number|NumberCollection
{

}
```

I confess I may be oversimplifying it too much, but I thought it was worth
asking. This could still be abused for crazy stuff, but by using
inheritance we make a best effort to delimit the scope into a mathematical
context.

My opinion is that operator overloading is bad for the language and is a
must-have feature for mathematical context. This seem to be the closest to
a common ground I can find.


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Jordan LeDoux
On Sat, Aug 7, 2021 at 8:20 PM Mike Schinkel  wrote:

> > On Aug 7, 2021, at 10:28 AM, Larry Garfield 
> wrote:
> I strongly echo Larry's concern here.
>
> While I tend to be one who wants more language features, not less, the
> availability of unconstrained operator overloading can beckon an
> inexperienced and/or undisciplined developer to add operators for many of
> the classes they implement, whether or not doing is actually applicable or
> a good idea.
>
> I am even concerned about constrained operator overloading for the same
> reason.  Here [1][2] are a couple essays to argue against operator
> overloading.
>
> Ruby has operator overloading, and one of the distasteful aspects I found
> regarding in programming in Ruby was that everybody's Ruby code you looked
> at felt like I was written in a slightly different language. I would hate
> that to become the case with PHP, more than it already is.
>
> I am actually surprised that the last operator overload RFC came close to
> passing because adding it seems like it would open a Pandora's box and yet
> other proposals that are less Pandoric seem to be anathema on this list.
>
> That said, I am not unsympathetic to the fact that operator overloading
> may well have some extremely valid use-cases, just ones that I do not
> personally seem to need on a day-to-day basis when writing code.
>
> Operator overloading seems to me to be of more value to those who are
> essentially wanting to write DSLs (domain-specific languages.) If that is
> indeed the case, and there are some DSL like features I wish we could add
> to PHP that would generally be non-starters for non-DSL usage.
>
> I wonder if there is a way to limit to only DSL use-cases?  I doubt there
> is, but I had to pose the question in case someone else can envision a way
> to do so.
>
> So my main questions are:
>
> 1.) What are use-cases where operator overloading would really be
> valuable?
>
> 2.) Would it possible that instead of adding operator overloading we could
> add classes that could be extended where PHP actually defines the operators
> for those classes?
>
> If we can do #2 we can really work through all the issues with
> commutativity, associativity, etc. and also implement all and only the
> operators that make sense for the use-case.
>
>
> -Mike
>
> [1]
> https://cafe.elharo.com/programming/operator-overloading-considered-harmful/
> [2]
> https://www.joelonsoftware.com/2005/05/11/making-wrong-code-look-wrong/
> [3] https://externals.io/message/115554#115603
> [4] https://english.stackexchange.com/a/170247/1164
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>
Hey Mike,

Off the top of my head here are some of the use cases that I think benefit
greatly from this:

- Complex number objects
- Fractions objects
- Matrix objects (math)
- Vector objects (math)
- Time/Date intervals
- Collections
- Arbitrary precision numbers (which are usually represented as a string in
PHP)

Here are some actual user libraries which would probably use them:

- samsara/fermat (this library is mine as a matter of disclosure)
- brick/math
- markbaker/complex
- markbaker/matrix
- krowinski/bcmath-extended
- malenki/math
- markrogoyski/math-php
- rubix/tensor
- numphp/numphp
- mcordingley/linearalgebra

The objects which represent a mathematical object that *cannot* be cast to
either an integer or a float without losing their meaning are the ones that
stand to gain the most. If you have an arbitrary precision number that will
overflow both ints and floats, then even providing a method to cast them
first doesn't help (that is, adding a __toInt() and toFloat() method would
not help). Matrices and vectors cannot be converted to a meaningful scalar
in any way that would allow the use of operators. Complex numbers *not
only* can't be converted to an int or float, but as I've said in a few
places, the correct behavior for the >, <, >=, and <= operators would be to
throw an exception as these types of comparison are mathematically
undefined for ZFC set theory.

As for constraints... well, if I had absolutely no concern for
implementation at all, and was just designing what constraints to put on
the magic methods, they would be:

1. void is an unsupported return, and failing to return a value results in
an error.
2. Variables outside the scope of the method cannot be set. This includes
properties on the object which is defining the magic method, and includes
sets that occur in called functions and methods.

I think that the second restriction there would be quite difficult to
accomplish in an implementation. Perhaps it could be done by creating a
readonly temporary copy of the objects in question and then executing the
magic method on that.

In any case, it is certainly possible that we could instead implement some
magic *objects* which can be extended that have built-in overloading in
specific ways. I think this is actually worse for the following 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-08 Thread Jordan LeDoux
On Sat, Aug 7, 2021 at 8:26 PM Dusk  wrote:

> On Aug 7, 2021, at 15:28, Larry Garfield  wrote:
> > As an example here, time units.  Adding two hour:minute time tuples
> together to get a new time (wrapping at the 24 hour mark) is an entirely
> reasonable thing to do.  But multiplication and division on time doesn't
> make any sense at all.  Or, maybe it does but only with ints (2:30 * 3 =
> 7:30?), kind of, but certainly not on the same type.
>
> This touches on another important question -- how do we plan to represent:
>
> 1) An operator which is only applicable when an operator is used on two
> dissimilar types (e.g. TimeTuple x float)?
>
> 2) An operator which can be applied to an object, but with a primitive or
> otherwise non-extensible type on the left hand side of the operator (e.g.
> float x TimeTuple)?
>
> 3) An operator which can be used with multiple types, but whose meaning
> and/or return value can change based on what types are used (e.g. Matrix x
> Matrix vs. float x Matrix)?
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>
The short answer is that all three of these concerns *must* be left up to
the userland implementations. Our job, realistically, should be to provide
a sane and consistent way for their implementations to accomplish this. But
truly, for most of these conditions the interpreter can't make enough
assumptions about the purpose to make any meaningful contribution on
questions like these.

Because of this, as far as actual implementation goes, I was gravitating
towards one of two possible formats:

function __op($rhs) {
} // Binary operators

function __op() {
} // Unary operators

In this implementation, an object could *only* overload the operator if it
was on the left hand side. There are some advantages to this. It simplifies
the cases within the do_operation function that would need to be considered
for instance.

function __op($pos, $lhs, $rhs) {
} // Binary operators

function __op() {
} // Unary operators

In this implementation, the $pos argument would be 0 if the called object
was on the left, and 1 if the called object was on the right. The right
hand side would obviously not be passed for unary operations (though there
aren't any unary operations that I plan to implement in this RFC). The
major advantage of this implementation is that the code which is most aware
of the context and meaning could fully handle the situation, regardless of
whether the object was on the left or right. This would allow us to provide
something that is *more* commutative, even if full commutativity isn't
desirable for the reasons I've outlined earlier.

Jordan


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Dusk
On Aug 7, 2021, at 15:28, Larry Garfield  wrote:
> As an example here, time units.  Adding two hour:minute time tuples together 
> to get a new time (wrapping at the 24 hour mark) is an entirely reasonable 
> thing to do.  But multiplication and division on time doesn't make any sense 
> at all.  Or, maybe it does but only with ints (2:30 * 3 = 7:30?), kind of, 
> but certainly not on the same type.

This touches on another important question -- how do we plan to represent:

1) An operator which is only applicable when an operator is used on two 
dissimilar types (e.g. TimeTuple x float)?

2) An operator which can be applied to an object, but with a primitive or 
otherwise non-extensible type on the left hand side of the operator (e.g. float 
x TimeTuple)?

3) An operator which can be used with multiple types, but whose meaning and/or 
return value can change based on what types are used (e.g. Matrix x Matrix vs. 
float x Matrix)?
--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Mike Schinkel
> On Aug 7, 2021, at 10:28 AM, Larry Garfield  wrote:
> 
> The downside is that 30 seconds after that, 15 other libraries would do the 
> same in subtly incompatible ways, and then both Laravel and Symfony would 
> release their own that are incompatible with each other, and it would just be 
> a total mess because you would have NFI what any given operator is going to 
> do.  Then FIG would try to define a few to standardize the madness, would 
> take about 10-12 months to do so, but both Symfony and Laravel would go on 
> using their own instead because they're big enough that they can do that, and 
> we'll have a mess basically forever.  That is what my crystal ball tells me 
> would happen.
> 
> So while this approach appeals to me personally, I think in the long run it's 
> probably a bad idea.  My understanding is that many people consider C++'s 
> adoption of this approach a mistake, although I'm not a C++ developer so 
> cannot speak from first hand experience.

I strongly echo Larry's concern here. 

While I tend to be one who wants more language features, not less, the 
availability of unconstrained operator overloading can beckon an inexperienced 
and/or undisciplined developer to add operators for many of the classes they 
implement, whether or not doing is actually applicable or a good idea.

I am even concerned about constrained operator overloading for the same reason. 
 Here [1][2] are a couple essays to argue against operator overloading.

Ruby has operator overloading, and one of the distasteful aspects I found 
regarding in programming in Ruby was that everybody's Ruby code you looked at 
felt like I was written in a slightly different language. I would hate that to 
become the case with PHP, more than it already is.

I am actually surprised that the last operator overload RFC came close to 
passing because adding it seems like it would open a Pandora's box and yet 
other proposals that are less Pandoric seem to be anathema on this list.

That said, I am not unsympathetic to the fact that operator overloading may 
well have some extremely valid use-cases, just ones that I do not personally 
seem to need on a day-to-day basis when writing code.

Operator overloading seems to me to be of more value to those who are 
essentially wanting to write DSLs (domain-specific languages.) If that is 
indeed the case, and there are some DSL like features I wish we could add to 
PHP that would generally be non-starters for non-DSL usage.

I wonder if there is a way to limit to only DSL use-cases?  I doubt there is, 
but I had to pose the question in case someone else can envision a way to do so.

So my main questions are:  

1.) What are use-cases where operator overloading would really be valuable?  

2.) Would it possible that instead of adding operator overloading we could add 
classes that could be extended where PHP actually defines the operators for 
those classes?  

If we can do #2 we can really work through all the issues with commutativity, 
associativity, etc. and also implement all and only the operators that make 
sense for the use-case.


> On Fri, Aug 6, 2021, at 3:18 PM, Scott Arciszewski wrote:
>> My recommendation is to have a base interface for every operator that can
>> be overloaded, so that these can be composed together.
>> 
>> AddOverloadInterface { __overloadAdd(): self; }
>> SubOverloadInterface { __overloadSub(): self; }
>> MulOverloadInterface { __overloadMul(): self; }
>> DivOverloadInterface { __overloadDiv(): self; }
>> ModOverloadInterface { __overloadMod(): self; }
>> LeftShiftOverloadInterface { __overloadLeftShift(): self; }
>> RightShiftOverloadInterface { __overloadRightShift(): self; }
>> XorOverloadInterface { __overloadXor(): self; }
>> etc.
> 
> That would be roughly how Stringable/__toString works now.  I'd be OK with 
> that, if it's going to be a language trend.

If this is how it turns out, I would hope for consistent naming, e.g. Addable 
vs. AddOverloadInterface, Subtractable vs. SubOverloadInterface, and so on.


> On Aug 7, 2021, at 1:48 PM, Dan Ackroyd  wrote:
> On Fri, 6 Aug 2021 at 21:18, Scott Arciszewski  wrote:
>> It's probably worth exploring whether common combinations are worth
>> defining for convenience.
> My understanding of the current consensus is "let's not".
> 
> That's based from the discussion on whether defining 'number' as 'int
> | float' would be worth doing, mostly because adding aliases don't
> provide much value, 

While it may (or may not?) be consensus, I argue the counter which is that 
adding `number` to PHP to mean `int|float` would provide the value of:

1.) Standardization and 
2.) interoperability between libraries that use `number`.  

This argument *assumes* there would be a strong consensus that `number` should 
actually mean `int|float` and not something else, or not some other name.

For clarity I am not arguing that number *means* int|float — I'd have to review 
the debate and see if there was strong consensus — but 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Jordan LeDoux
On Sat, Aug 7, 2021 at 3:29 PM Larry Garfield 
wrote:

>
> Side note: Please remember to bottom-post.
> (trimmed message)
>

> --Larry Garfield
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>
Sorry about top-posting. :)

Your arguments for why grouping is undesirable are very persuasive. While I
don't think that having exceptions thrown from stubs is necessarily a bad
thing, I definitely understand how this suggests that the grouping is
unsuccessful at "hinting" the developer on implementation, and also how the
grouping may be too restrictive as a language-level feature. ArrayAccess
really is an interesting comparison.

I did very briefly consider the idea of implementing a *single* magic
method: __doOperation(string $operator, mixed $lhs, $rhs = null)

After thinking on it briefly, I came to many of the same conclusions: this
would result almost invariably in further fracturing between a "Laravel"
way of doing things and a "Symfony" way of doing things which would be
wholly incompatible and inconsistent. It would also be... complex for IDE's
to support in any meaningful way, especially for custom operators that are
not part of the interpreter. (It also would be far more complex for me to
implement as it would probably require some careful changes to the
compiler.)

So I'll simply disqualify the idea of custom operators right now. I do
understand, like you, why some people might want them and use them, but I
feel like it's too complex and risky of a change, and at its core, not a
change that I want to make, so someone else would need to actually do the
RFC if that was the case.

> The 4 arithmetic operators, concat, and compare.

I would argue that both modulo and pow (% and **) are arithmetic operators
that should come with the basic four as well. Meanwhile, I think the concat
operator is both more prone to error *and* less useful. Currently, if you
try to concat an object, it will be cast to a string, and since
__toString() already exists, this behavior can effectively be controlled
already. The main reason that other operators couldn't easily be solved
with supplementary __to*() methods is that for *many* usecases where you'd
benefit from overloading operators, the scalar types don't adequately
capture the state (which is presumably the reason that the program is
representing them as objects).

Further, as detailed in my earlier reply, I don't think we can get away
with only allowing compare. Complex numbers are a trivial example of why,
but there are many others where only some of the comparison operators make
sense. We could, however, allow compare as a minimal implementation to
support the others. If it is implemented, then the others can be derived,
but if it is not then the other comparison operators should be able to be
implemented individually.

> None of these approaches resolves the commutability problem. There is no
guarantee that $a + $b === $b + $a, if $a or $b are objects that implement
Addable.

I don't think this is a problem which can be resolved without some
extremely strict limitations on the operator overloading. (Something like,
objects can only be on both sides if they are the *same* class.) Even then,
there is little we could do to prevent the user code from doing something
like:

function __add($rhs) {
return (random_int(0, 1) == 1 ? true : 5);
}

As such, I think the idea of operator overloading is fundamentally
incompatible with the concern of ensuring commutability. In fact, *many* of
the usecases for this feature would *depend* on them not being commutable.
For matrices, A * B != B * A except under specific values. This is in fact
part of the definition of multiplication under matrices, so I feel that
wanting to ensure commutative behavior actually represents misunderstanding
the feature itself. Extending the native operators to work with matrices
using an internal implementation would *also* result in non-commutative
behavior, because that's the *correct* behavior for matrices.

I do not see this as inherently a problem to be solved, but it is a thing
to keep in mind when considering the implementation.

> Should the methods in question be dynamic or static? In my mind, the only
argument for static is that it makes it more likely that they'll be
implemented in an immutable way.

I also think that dynamic methods are entirely possible here. While
immutability is an inherent property of using operators in nearly any
context, it's not something that we can guarantee when we leave the
implementation of operator handling up to userspace, and requiring statics
won't do that either. Laravel as an example uses static properties and the
__callStatic() method to provide mutable static calls everywhere in the
entire framework with Facades (something there are very strong opinions
about in userland).

As such I think that requiring static methods is a way to make internals
"feel better" about it without 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Larry Garfield
On Sat, Aug 7, 2021, at 3:07 PM, Jordan LeDoux wrote:
> > a) Treating operators as arbitrary symbols, which can be assigned any
> operation which makes sense in a particular domain.
> > b) Treating operators as having a fixed meaning, and allowing custom
> types to implement them with that meaning.
> 
> I think this is the core design choice that will affect how the
> implementation is approached, and having some good discussion around it
> before I got into the implementation was the goal of this thread. :) Jan's
> proposal for 8.0 fell more into the a) category with each symbol being
> given an independent, unrelated, and unopinionated override. That RFC very
> nearly passed, the vote was 38 for and 28 against.
> 
> My one hesitation in pushing for a b) type implementation right now (which
> I favor slightly personally) is that the basic math operators do have very
> different meanings between arithmetic, matrix/vector math, and complex
> numbers, all of which are in the same domain of "math". Granted, only
> objects which represent a number valid for arithmetic could also be used
> with other math functions in PHP (such as the sqrt() or cos() functions).
> However, they are definitely use cases that are well treaded in userspace
> code and libraries.
> 
> Complex numbers, for example, couldn't implement a __compare() function at
> all, as they don't have any consistent and sensical definition of "greater
> than" or "less than". This means that if an object represented a complex
> number, the following code would be perhaps unexpected to some:
> 
> if (10 < $complex) {
> // Never gets here
> }
> 
> if (10 > $complex) {
> // Never gets here
> }
> 
> if (10 == $complex) {
> // Never gets here (!!)
> }
> 
> $comparison = 10 <=> $complex; // Nonsensical, should throw an exception
> 
> So while I tend to lean more towards a b) type implementation myself, even
> within that I understood there to be some non-trivial considerations.
> "Numbers" in PHP are obviously real numbers, instead of matrices or
> complex, so all previous semantics of operators and math functions would
> reflect that. To me, an ideal implementation of operator overloading would
> be both:
> 
> 1. Flexible about the contextual meaning of a given operator.
> 2. Somewhat opinionated about the semantical meaning of an operator.
> 
> This is obviously challenging to accomplish, which is why I'm leaving
> myself nearly a whole year for discussion and implementation. I don't want
> to do this quickly and end up with something that gets accepted because we
> want some form of operator overloading, or something that gets rejected
> again despite putting in a great deal of work.
> 
> Jordan

Side note: Please remember to bottom-post.

I think Rowan's breakdown is a bit too pessimistic and binary.  There are 
definitely different possible ways to interpret operator overloading, but IMO 
there is a reasonable middle-ground.

At one end is the most restrictive, which would be clustering all "related" 
overloads together.  That would be something like this:

interface Arithmetic {
  public function __add($arg);
  public function __subtract($arg);
  public function __multiply($arg);
  public function __delete($arg);
}

The intent of clustering like that would be to "force" developers to use it 
only on number-like things.  However, I believe that has a number of problems.

1) What is a number-like thing?  How number-ish does it have to be?

As an example here, time units.  Adding two hour:minute time tuples together to 
get a new time (wrapping at the 24 hour mark) is an entirely reasonable thing 
to do.  But multiplication and division on time doesn't make any sense at all.  
Or, maybe it does but only with ints (2:30 * 3 = 7:30?), kind of, but certainly 
not on the same type.  I'm sure we could come up with an infinite number of 
cases where one or more arithmetic operations are entirely reasonable and 
well-defined, but others are not.

2) We know from experience that it doesn't work.

PHP already has ArrayAccess, which has four methods.  It's extremely common for 
people to implement ArrayAccess and stub out some of the methods with 
exceptions because they don't make sense in context.  I've seen it a bunch, and 
I've done it a bunch myself  ArrayAccess is, basically, operator overloading 
for four different operators: [], [$key], isset(), and unset().  But plenty of 
use cases exist for wanting to do only some of those (eg, a read-only map so 
stub out unset and offsetSet()), and generally speaking, developers have 
responded to that conundrum by saying "screw it, Exceptions for everybody!"

If we went with a combined interface, I am 100% certain we would see people 
implementing Arithmetic and throwing exceptions from __multiply() and 
__divide().

At the other extreme is arbitrary operator definition a la C++.  That would 
look something vaguely like:

class Foo {
  public function __override(+)($arg);
}

That would give the most 

Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Jordan LeDoux
> a) Treating operators as arbitrary symbols, which can be assigned any
operation which makes sense in a particular domain.
> b) Treating operators as having a fixed meaning, and allowing custom
types to implement them with that meaning.

I think this is the core design choice that will affect how the
implementation is approached, and having some good discussion around it
before I got into the implementation was the goal of this thread. :) Jan's
proposal for 8.0 fell more into the a) category with each symbol being
given an independent, unrelated, and unopinionated override. That RFC very
nearly passed, the vote was 38 for and 28 against.

My one hesitation in pushing for a b) type implementation right now (which
I favor slightly personally) is that the basic math operators do have very
different meanings between arithmetic, matrix/vector math, and complex
numbers, all of which are in the same domain of "math". Granted, only
objects which represent a number valid for arithmetic could also be used
with other math functions in PHP (such as the sqrt() or cos() functions).
However, they are definitely use cases that are well treaded in userspace
code and libraries.

Complex numbers, for example, couldn't implement a __compare() function at
all, as they don't have any consistent and sensical definition of "greater
than" or "less than". This means that if an object represented a complex
number, the following code would be perhaps unexpected to some:

if (10 < $complex) {
// Never gets here
}

if (10 > $complex) {
// Never gets here
}

if (10 == $complex) {
// Never gets here (!!)
}

$comparison = 10 <=> $complex; // Nonsensical, should throw an exception

So while I tend to lean more towards a b) type implementation myself, even
within that I understood there to be some non-trivial considerations.
"Numbers" in PHP are obviously real numbers, instead of matrices or
complex, so all previous semantics of operators and math functions would
reflect that. To me, an ideal implementation of operator overloading would
be both:

1. Flexible about the contextual meaning of a given operator.
2. Somewhat opinionated about the semantical meaning of an operator.

This is obviously challenging to accomplish, which is why I'm leaving
myself nearly a whole year for discussion and implementation. I don't want
to do this quickly and end up with something that gets accepted because we
want some form of operator overloading, or something that gets rejected
again despite putting in a great deal of work.

Jordan

On Sat, Aug 7, 2021 at 12:07 PM Rowan Tommins 
wrote:

> On 06/08/2021 17:34, Jordan LeDoux wrote:
> > 1. The only supported operators in the RFC will be the mathematical
> > operators: (+, -, /, *, **, %)
> > 2. The RFC would also provide an interface, (something like
> > MathObjectInterface), that has all the magic methods in it.
> > 3. The do_operation would be changed to check for the interface being
> > implemented instead of the specific method.
>
>
> Hi Jordan,
>
> In a previous thread [1], I wrote about two fundamental design
> approaches to operator overloading:
>
> a) Treating operators as arbitrary symbols, which can be assigned any
> operation which makes sense in a particular domain.
> b) Treating operators as having a fixed meaning, and allowing custom
> types to implement them with that meaning.
>
> Both approaches have their pros and cons, but my general impression is
> that approach (b) has more support on this list.
>
> For approach (b), I think your proposal to group operations into
> interfaces is a good one - it doesn't prevent someone using the
> operators to mean something completely different, but it expresses a
> clear opinion.
>
> I think using "+" for a union of two collections is really an example of
> approach (a) - it doesn't really mean "add", and it's no less arbitrary
> than using "<<" to add an item to a collection (as is conventional in
> Ruby, for instance).  If we want to go down that route, and allow
> individual operators to be overloaded, I think we should look for a
> syntax that lets you pick the symbol, rather than giving them names
> which only make sense in some contexts.
>
>
> [1] https://news-web.php.net/php.internals/108347
>
> --
> Rowan Tommins
> [IMSoP]
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Rowan Tommins

On 06/08/2021 17:34, Jordan LeDoux wrote:

1. The only supported operators in the RFC will be the mathematical
operators: (+, -, /, *, **, %)
2. The RFC would also provide an interface, (something like
MathObjectInterface), that has all the magic methods in it.
3. The do_operation would be changed to check for the interface being
implemented instead of the specific method.



Hi Jordan,

In a previous thread [1], I wrote about two fundamental design 
approaches to operator overloading:


a) Treating operators as arbitrary symbols, which can be assigned any 
operation which makes sense in a particular domain.
b) Treating operators as having a fixed meaning, and allowing custom 
types to implement them with that meaning.


Both approaches have their pros and cons, but my general impression is 
that approach (b) has more support on this list.


For approach (b), I think your proposal to group operations into 
interfaces is a good one - it doesn't prevent someone using the 
operators to mean something completely different, but it expresses a 
clear opinion.


I think using "+" for a union of two collections is really an example of 
approach (a) - it doesn't really mean "add", and it's no less arbitrary 
than using "<<" to add an item to a collection (as is conventional in 
Ruby, for instance).  If we want to go down that route, and allow 
individual operators to be overloaded, I think we should look for a 
syntax that lets you pick the symbol, rather than giving them names 
which only make sense in some contexts.



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

--
Rowan Tommins
[IMSoP]

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Dan Ackroyd
On Fri, 6 Aug 2021 at 21:18, Scott Arciszewski  wrote:
>
> It's probably worth exploring whether common combinations are worth
> defining for convenience.
>

My understanding of the current consensus is "let's not".

That's based from the discussion on whether defining 'number' as 'int
| float' would be worth doing, mostly because adding aliases don't
provide much value, and once you've started adding some, where do you
stop? e.g. if we defined 'number' why not also define 'scalar'?

The value for interfaces is even lower than other types, as it's
already possible in userland to define your own combination types:

interface MatrixMath extends __AddInterface, __AddSubInterface,
__AddMulInterface {}

as interfaces can extend multiple other interfaces at once.

cheers
Dan
Ack

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Dan Ackroyd
On Fri, 6 Aug 2021 at 17:34, Jordan LeDoux  wrote:
>
> I was considering working from Jan's previous
> implementation with these basic changes:

That may not be the best place to start, and that something more
similar to the previous (unvoted) RFC may be better:
https://wiki.php.net/rfc/operator-overloading

In particular, the problems with the approach in
https://wiki.php.net/rfc/userspace_operator_overloading is that having
a function return a special constant when unsupported types are used
is...just not the right approach. The function shouldn't be run at all
if the types aren't supported.

Having to understand a block of code, to figure out what types it
accepts, makes code hard to reason about.

Although the union types RFC had passed when the userspace operator
overloading RFC went to vote, the ability to use union types wasn't
taken advantage of in the RFC.

Listing the types supported as a union type for the parameter like:

class Order implements __AddInterface {
public function __add(Product|Discount $rhs) {...}
}

is easier to reason about, and would throw a type-error consistent
with how unacceptable types would behave for other function calls.

I personally find having the functions be defined as static, with the
first parameter being the left hand side, a bit weird. It makes the
code quite a bit harder to read imo*.

> I feel like the right place to start is to limit
> the RFC to only the mathematical operators at first.
> ...something like MathObjectInterface

I agree with Larry and Scott, one method per interface is a better
approach. But defining all the interfaces in one go is probably
better, even if the implementation only supports using some of them.

Doing it like that means that when new operators are implemented as
overloadable in PHP 8.3, people would be able to write library code
that takes advantage of those new operators that works on both 8.2 and
8.3, without users having to define the missing interfaces themselves,
even if their app code isn't able to take advantage of the newly
overloadable operators until they upgrade to 8.3.

cheers
Dan
Ack

* This was mentioned in the RFC: "By passing both operands to the
handler, it can decide between the cases on non-commutative operators
($a / 2 vs. 2 / $a), which would be more difficult when only the
“other” operand (besides $this) is passed.", but I can't see an
example of that, and I don't understand it. Perhaps a better
explanation would be enough.

Though also the behaviour for associativity mentioned in the previous
RFC  https://wiki.php.net/rfc/operator-overloading#associativity isn't
mentioned in the 2020 RFC and there may be a can of worms in that.

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-07 Thread Larry Garfield
On Fri, Aug 6, 2021, at 3:18 PM, Scott Arciszewski wrote:
> My recommendation is to have a base interface for every operator that can
> be overloaded, so that these can be composed together.
> 
> AddOverloadInterface { __overloadAdd(): self; }
> SubOverloadInterface { __overloadSub(): self; }
> MulOverloadInterface { __overloadMul(): self; }
> DivOverloadInterface { __overloadDiv(): self; }
> ModOverloadInterface { __overloadMod(): self; }
> LeftShiftOverloadInterface { __overloadLeftShift(): self; }
> RightShiftOverloadInterface { __overloadRightShift(): self; }
> XorOverloadInterface { __overloadXor(): self; }
> etc.
> 
> Then if you were implementing matrix math, you could do this:
> 
> MatrixMath implements AddOverloadInterface, SubOverloadInterface,
> MulOverloadInterface {
> 
> }

That would be roughly how Stringable/__toString works now.  I'd be OK with 
that, if it's going to be a language trend.

> This prevents you from having to define methods for operations you don't
> support.
> 
> It's probably worth exploring whether common combinations are worth
> defining for convenience.

Now that intersection types are a thing, I don't think combo interfaces are 
worth much here.  If anything, it would be just more impetus for type aliases 
to reduce typing.  (Human typing, I mean, not code typing.)

--Larry Garfield

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



Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-06 Thread Scott Arciszewski
My recommendation is to have a base interface for every operator that can
be overloaded, so that these can be composed together.

AddOverloadInterface { __overloadAdd(): self; }
SubOverloadInterface { __overloadSub(): self; }
MulOverloadInterface { __overloadMul(): self; }
DivOverloadInterface { __overloadDiv(): self; }
ModOverloadInterface { __overloadMod(): self; }
LeftShiftOverloadInterface { __overloadLeftShift(): self; }
RightShiftOverloadInterface { __overloadRightShift(): self; }
XorOverloadInterface { __overloadXor(): self; }
etc.

Then if you were implementing matrix math, you could do this:

MatrixMath implements AddOverloadInterface, SubOverloadInterface,
MulOverloadInterface {

}

This prevents you from having to define methods for operations you don't
support.

It's probably worth exploring whether common combinations are worth
defining for convenience.

On Fri, Aug 6, 2021 at 1:49 PM Larry Garfield 
wrote:

> On Fri, Aug 6, 2021, at 11:34 AM, Jordan LeDoux wrote:
> > Hey all,
> >
> > I contacted Jan a few days ago to ask if they were going to try again for
> > their RFC, but I wanted to get a quick temperature check on this.
> >
> > I would like to work on this RFC for 8.2, and after going through
> previous
> > discussions on the topic, I feel like the right place to start is to
> limit
> > the RFC to only the mathematical operators at first.
> >
> > Based on previous comments, I was considering working from Jan's previous
> > implementation with these basic changes:
> >
> > 1. The only supported operators in the RFC will be the mathematical
> > operators: (+, -, /, *, **, %)
> > 2. The RFC would also provide an interface, (something like
> > MathObjectInterface), that has all the magic methods in it.
> > 3. The do_operation would be changed to check for the interface being
> > implemented instead of the specific method.
> >
> > All of these operators belong to the same "group" of changes, and
> (broadly)
> > any object that is valid to override for one of them should be valid to
> > override for any of them. NOTE: There are edge cases of this statement
> > certainly.
> >
> > This would help address some of the concerns that were expressed about
> > misuse of things like the + operator to add things to a cache. It would
> > more explicitly take a position on how these operators should be used in
> > userland code to keep them more consistent with the behavior of these
> > operators in normal PHP code.
> >
> > This would be my first contribution and my first RFC, so I wanted to get
> > some very broad feedback on this before diving in.
> >
> > It would suggest that future sets of operators could come with their own
> > interfaces to also attempt to guarantee an all-or-nothing approach in
> > userland code, (BitwiseObjectInterface, ComparableObjectInterface,
> > LogicalObjectInterface, etc.). Though decisions on any of those operators
> > or their implementations would be left as future scope.
> >
> > Jordan
>
> If you wanted to cluster them, I would strongly recommend much smaller
> groupings.  IMO, adding two collections to get another collection -- like
> we add/merge arrays -- is a completely reasonable thing to do, but would
> only use + and potentially - (for removing items from a collection and
> returning the smaller collection). But * and / make no sense in that
> context.
>
> Even if you confine yourself to mathematical concepts, matrix
> multiplication is a well-established thing that would make sense for
> math-centric applications to do.  But matrix division is... somewhat more
> fiddly, and has multiple possible definitions.  (Note: I've not done matrix
> math in over 20 years, so I'm basing that statement on some quick googling.)
>
> So I don't think force-grouping the overloads makes sense, in practice.
> I'm still open to operator overloading in general, but I don't think the
> clustering is going to help.  The weird and complicated type interactions,
> particularly when it comes to commutablity, are a much larger issue, IMO.
>
> --Larry Garfield
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>


Re: [PHP-DEV] Revisiting Userland Operator Overloads

2021-08-06 Thread Larry Garfield
On Fri, Aug 6, 2021, at 11:34 AM, Jordan LeDoux wrote:
> Hey all,
> 
> I contacted Jan a few days ago to ask if they were going to try again for
> their RFC, but I wanted to get a quick temperature check on this.
> 
> I would like to work on this RFC for 8.2, and after going through previous
> discussions on the topic, I feel like the right place to start is to limit
> the RFC to only the mathematical operators at first.
> 
> Based on previous comments, I was considering working from Jan's previous
> implementation with these basic changes:
> 
> 1. The only supported operators in the RFC will be the mathematical
> operators: (+, -, /, *, **, %)
> 2. The RFC would also provide an interface, (something like
> MathObjectInterface), that has all the magic methods in it.
> 3. The do_operation would be changed to check for the interface being
> implemented instead of the specific method.
> 
> All of these operators belong to the same "group" of changes, and (broadly)
> any object that is valid to override for one of them should be valid to
> override for any of them. NOTE: There are edge cases of this statement
> certainly.
> 
> This would help address some of the concerns that were expressed about
> misuse of things like the + operator to add things to a cache. It would
> more explicitly take a position on how these operators should be used in
> userland code to keep them more consistent with the behavior of these
> operators in normal PHP code.
> 
> This would be my first contribution and my first RFC, so I wanted to get
> some very broad feedback on this before diving in.
> 
> It would suggest that future sets of operators could come with their own
> interfaces to also attempt to guarantee an all-or-nothing approach in
> userland code, (BitwiseObjectInterface, ComparableObjectInterface,
> LogicalObjectInterface, etc.). Though decisions on any of those operators
> or their implementations would be left as future scope.
> 
> Jordan

If you wanted to cluster them, I would strongly recommend much smaller 
groupings.  IMO, adding two collections to get another collection -- like we 
add/merge arrays -- is a completely reasonable thing to do, but would only use 
+ and potentially - (for removing items from a collection and returning the 
smaller collection). But * and / make no sense in that context.

Even if you confine yourself to mathematical concepts, matrix multiplication is 
a well-established thing that would make sense for math-centric applications to 
do.  But matrix division is... somewhat more fiddly, and has multiple possible 
definitions.  (Note: I've not done matrix math in over 20 years, so I'm basing 
that statement on some quick googling.)

So I don't think force-grouping the overloads makes sense, in practice.  I'm 
still open to operator overloading in general, but I don't think the clustering 
is going to help.  The weird and complicated type interactions, particularly 
when it comes to commutablity, are a much larger issue, IMO.

--Larry Garfield

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



[PHP-DEV] Revisiting Userland Operator Overloads

2021-08-06 Thread Jordan LeDoux
Hey all,

I contacted Jan a few days ago to ask if they were going to try again for
their RFC, but I wanted to get a quick temperature check on this.

I would like to work on this RFC for 8.2, and after going through previous
discussions on the topic, I feel like the right place to start is to limit
the RFC to only the mathematical operators at first.

Based on previous comments, I was considering working from Jan's previous
implementation with these basic changes:

1. The only supported operators in the RFC will be the mathematical
operators: (+, -, /, *, **, %)
2. The RFC would also provide an interface, (something like
MathObjectInterface), that has all the magic methods in it.
3. The do_operation would be changed to check for the interface being
implemented instead of the specific method.

All of these operators belong to the same "group" of changes, and (broadly)
any object that is valid to override for one of them should be valid to
override for any of them. NOTE: There are edge cases of this statement
certainly.

This would help address some of the concerns that were expressed about
misuse of things like the + operator to add things to a cache. It would
more explicitly take a position on how these operators should be used in
userland code to keep them more consistent with the behavior of these
operators in normal PHP code.

This would be my first contribution and my first RFC, so I wanted to get
some very broad feedback on this before diving in.

It would suggest that future sets of operators could come with their own
interfaces to also attempt to guarantee an all-or-nothing approach in
userland code, (BitwiseObjectInterface, ComparableObjectInterface,
LogicalObjectInterface, etc.). Though decisions on any of those operators
or their implementations would be left as future scope.

Jordan