On Mon, Sep 16, 2024 at 9:35 PM Mike Schinkel <m...@newclarity.net> wrote:

>
> Yes, if constraints of the nature I propose below are adopted.
>
> The biggest problem I have with operator overloads is that — once added —
> all code could potentially be "infected" with operator overloads. However,
> if the developer *using* an operator overload could instead opt-in to using
> them, in context, then I would flip my opinion and I would begin to support
> them.
>
> What might opt-in look like?  I propose two (2) mechanisms of which each
> would be useful for different use-cases. As such I do not see these two as
> competing but instead would expect adding both to be preferable:
>
> 1. Add a pair of sigils to enclose any expression that would need to
> support userland operator overloading. This would allow a developer to
> isolate just the expression that needs to use operator overloading. I
> propose {[...]} for this, but feel free to bikeshed sigils. Using an
> example from the RFC, here is what code might look like:
>
> $cnum1 = new ComplexNumber(1, 2);
> $cnum2 = new ComplexNumber(3, 4);
> $cnum3 = {[ $cnum1 * $cnum2 ]};               // Uses operator operloading
> sigils
> echo $cnum3->realPart.' + '.$cnum3->imaginaryPart.'i';
>
> 2. For when using `{[...]}` would be annoying because it would be needed
> in so many places, PHP could also add support for an attribute. e.g.
> `#[OperatorOverloads(Userland:true)]`. This attribute would apply to
> functions, methods, classes, enums, (other?) and indicates that operator
> overloads can be present anywhere in the body of the decorated structure. I
> included `Userland:true` as an indicator to a reader that this only applies
> to userland operator overloads and that built-in ones like in GMP and
> anywhere else would not need to be opted into, but that parameter could of
> course be dropped if others feel it is not needed. Again, feel free to
> bikeshed attribute name and/or parameters.
>
> #[OperatorOverloads(Userland:true)]
> function SprintProductOfTwoComplex(ComplexNumber $cnum1, ComplexNumber
> $cnum2)string {
>   $cnum3 = $cnum1 * $cnum2;
>   return sprintf("%d + %di", $cnum3->realPart, $cnum3->imaginaryPart);
> }
>
> If this approach were included in the RFC then it would also ensure there
> is no possibility of BC breakage. BC breakage which would certainly be an
> edge case but I can envision it would be possible,e specially where newer
> instances incorporating operator overloads are passed to functions that did
> not have parameters type hinted but were not intend to be used with
> operator overloads resulting in subtle potential breakage.
>
> This argument is also consistent with the argument people had about not
> allowing default values to be generically used in calls to the function
> function. Their claim was that developers who did not write their code with
> the intention of exposing defaults should not have their defaults exposed.
> Similarly developers that do not write their code to enable operator
> overloads should not be used with  userland operator overloads unless they
> explicitly allow it, especially as they may not have have tested code with
> operator overloads.
>
> Anyway, that is my two cents worth.
>
> TL;DR?  I argue that PHP should operator overloads but ONLY if there is a
> mechanism that requires the user of expressions that call overloaded
> operators to explicitly opt-in to their use.
>
> -Mike
>
>
This is interesting, as I've never seen this in any language I researched
as part of operator overloading, and also was never given this feedback or
anything similar by anyone who provided feedback before. My initial
reaction is that I do not understand how this is any better than parameter
typing. If you do not allow any objects into the scope you are using
operators, wouldn't that be the same as the kind of userland control you
are after? Or rather, how would it be substantially worse?

Your second example even includes a function that only accepts a
`ComplexNumber` object. I presume in your example there that if the
Attribute was removed, the function would just always produce a fatal
error, since that is the behavior of objects when used with `*`.

What it appears to me your proposal does is transform working operator
overloads into fatal errors if the user-code does not "opt-in". But any
such code would never actually survive long, wouldn't it? Without the
opt-in, these objects would ALWAYS produce fatal errors (which is what
happens now), which would eventually show up in testing, QA, etc. The
developer would realize that they (presumably) were trying to do a math
operation on something they thought was only a numeric type, and then guard
against objects being passed into that context with control statements,
parameter types, etc.

So it seems to me what this ACTUALLY guards against is developers who
inadvertently don't type-check their variables in code where the specific
type is relevant. After one round of testing, all of the code using
operators would either always allow objects and thus overloads, or never
allow objects and thus not use overloads. There shouldn't even be any
existing code that would be affected, since any existing code would need to
currently allow objects in a context where operators are used, which
currently produces a fatal error 100% of the time, (excepting internal
classes which are mostly final anyway, and thus unaffected by this
proposal).

What is the situation where your suggestion is implemented, a developer
does NOT opt-in to overloads, and they avoid unexpected behavior without
having to change their existing code to fix fatal errors? I don't see how
that is possible.

Also, replying into a 3 year old reddit thread I linked to for reference is
not what I intended, however I want to highlight one other thing you
commented there but not here for some reason:

> To illustrate my point, imagine if we also allowed control structure
overloads. If we had them we could no longer read code and know that an `if`
is a branch and a `for` is a loop; either could be anything valid for any
control structure. Talk about ambiguity!

Indeed. I want to make sure that I have not been ambiguous after reading
this, because I found it somewhat troubling:

I am looking at writing an RFC for specific *operators* that are finite and
defined within the RFC. I am not proposing something that would allow
control structures to be altered (I don't even think that would be possible
without essentially rewriting the entire Zend Engine specifically to do it).

Operators are not control structures. Operators mutate the value or state
of a variable in a repeatable way, given the input states. There is not
even a generalized mechanism in my RFC for "arbitrary" overloads, and the
compiler was not implemented in a way that is generalized for it either. It
allows only exactly the operators that are part of the RFC, and each are
handled specifically and individually.

Jordan

Reply via email to