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

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.

2) As Jordan demonstrated, there are many even formally defined situations 
where some of the operators are explicitly meaningless.  It would mean in those 
cases you cannot use this feature without lying, and setting landmines for 
other developers.

3) If you really do want to use all of those methods, yes, it would mean 8 
interfaces.  However, there's 2 easy solutions to that: A) We already know that 
type aliases would be useful.  B) We could make the interface implicit the way 
Stringable is.  That way you can just implement the method and move on, but 
people could still type against Addable or Divisible or whatever.

--Larry Garfield

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

Reply via email to