Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125577 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 1048B1A00BD for ; Tue, 17 Sep 2024 05:37:20 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1726551564; bh=tq7XVWX5eYq2OlBnhezYaNJ2EZYXEmvMZ73lscehP70=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=Zs4ry1xKAdeOToUFqciwom76fBuj+1zImwdfKwIAnsBHEATwjHvh0vOk614o/DxwR EISNMSCPWVVbSkwcxO82lxRf2vnQTUK2c9HuOB50FaBNxRrW0GRCbRb1GdzJbg5ggS jXjNfUCN47WzJxOY/b+5rKHuuJ5eZY17RcMJdQM/IVObppoEMRcPPKLwseOaqpEb8w ObO8mka4TGnnUmXC6GTSc3qaFLOxW/cFF8RejA1DAiPhxY1zSIDuueQ1ynizh7DuY4 0+fTyuS+8F+iwIlgtptjW1qhxzPdQBiDcxWF7Hn4+h+exwI5dVmoihpEXcrUr241s8 Z8NMufGiaVU5g== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id B94D8180053 for ; Tue, 17 Sep 2024 05:39:23 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-pf1-f181.google.com (mail-pf1-f181.google.com [209.85.210.181]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 17 Sep 2024 05:39:23 +0000 (UTC) Received: by mail-pf1-f181.google.com with SMTP id d2e1a72fcca58-7191ee537cbso3675195b3a.2 for ; Mon, 16 Sep 2024 22:37:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1726551437; x=1727156237; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=af0jsX+UvX+qPGW1BDH6GElUbmgWuCvsYGwBQ+jsf4c=; b=VaMo295VV+voz3X+9KB95GGIpC++EWmuxvURplZkcumr6qphuHDGkBDLkf5lACilwK tMqEZI8Xmze2+/V4vt7hxCavvo0wXtZ5h2CkVOUnRcP7aguY4V+fPbAeA6FtLLJ/ZGkA BXmZ/uki6PD0o6+ztklrB/at+RFNzVYOIMRnBzKad+UyYZefa2dkN7BWV2BO0q4pzevK ITHlFoDIkfvGDo4WuJYLrJp+kKKeJNNITU0ltyJnTsx4v/kSq7HiOO308URk2zTX/lbX g5W+bvMFgGA1W3qBaV3O4mkJZaBEuxt5RIu854w8/eUcm/72FHTa8sB3cQkWwidmwQLJ XlMA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726551437; x=1727156237; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=af0jsX+UvX+qPGW1BDH6GElUbmgWuCvsYGwBQ+jsf4c=; b=dKeafWZK/7vLNaNQOruvrtiJZjbL96phbSACYueWIS3KzibWEQnrSXXd6+LnIMbCDA irjlZu57rSWE+y9ZIOSvOVK+XlhqX8ABG0FLyrrNlR/vuGgpLG8VYB1vvXExM5kU/5KX NAVe3w+7Ros7q+UPIhqS3ROK83bGEgDWZghVa8SpB2XW+JeoANh1crglGHVaunXm04Ux J3iYTM1Wm7w31vJA5YkoT0iTD7tZ9JrI1KR9jL3q/zsnZsaNlAqvJly46tMMy0i/ifH3 bp8pylVbQqZJsZrLd3wyBh+BZ/0LqnHDjnMSRNWOgEAUpSwaOLWwSnfe5wzx4n0A1Cl7 Ap+g== X-Gm-Message-State: AOJu0YyT8PzwhVrEjI0fPosrEvdHYLnq1HMWK+CS5/xLLwZfqCwJ9YwE pnLCa85Pe3hD4VDlft0FTmosFmkLlVFmLQ9b8KP7BFWkN0Vm/IwP/S034ky4zOsdLDVyXk5NtGK mgs5+sAT7Zd3aXo7gN4XPUZGNnnI= X-Google-Smtp-Source: AGHT+IFGqL0Y7UOyRVwzX2223aTC9/vaPIuM0ZyeXCgNofVSuWzWzguF41BD3uI1D1e8aoCXoobj9KKbSzEt3pjm9jQ= X-Received: by 2002:a05:6a00:21d4:b0:717:93d7:166b with SMTP id d2e1a72fcca58-719262065c5mr25100386b3a.25.1726551437098; Mon, 16 Sep 2024 22:37:17 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <18603813-9ECB-4486-95EE-08BEDECAB88D@newclarity.net> In-Reply-To: <18603813-9ECB-4486-95EE-08BEDECAB88D@newclarity.net> Date: Mon, 16 Sep 2024 22:37:05 -0700 Message-ID: Subject: Re: [PHP-DEV] [Pre-RFC Discussion] User Defined Operator Overloads (again) To: Mike Schinkel Cc: PHP internals Content-Type: multipart/alternative; boundary="00000000000018479606224a1541" From: jordan.ledoux@gmail.com (Jordan LeDoux) --00000000000018479606224a1541 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Mon, Sep 16, 2024 at 9:35=E2=80=AFPM Mike Schinkel = wrote: > > Yes, if constraints of the nature I propose below are adopted. > > The biggest problem I have with operator overloads is that =E2=80=94 once= added =E2=80=94 > all code could potentially be "infected" with operator overloads. However= , > if the developer *using* an operator overload could instead opt-in to usi= ng > them, in context, then I would flip my opinion and I would begin to suppo= rt > 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 a= s > 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 =3D new ComplexNumber(1, 2); > $cnum2 =3D new ComplexNumber(3, 4); > $cnum3 =3D {[ $cnum1 * $cnum2 ]}; // Uses operator operload= ing > 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 appli= es > 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 o= f > 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 =3D $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 d= id > 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 wi= th > 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 the= y > explicitly allow it, especially as they may not have have tested code wit= h > 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 --00000000000018479606224a1541 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Mon, Sep 16, 2024 at 9:35=E2=80=AF= PM Mike Schinkel <mike@newclarity= .net> wrote:

Yes, if constraints of the = nature I propose below are adopted.

The biggest problem I have wi= th operator overloads is that =E2=80=94 once added =E2=80=94 all code could= potentially be "infected" with operator overloads. However, if t= he developer *using* an operator overload could instead opt-in to using the= m, in context, then I would flip my opinion and I would begin to support th= em. =C2=A0

What might opt-in look like?=C2=A0 I propose two (2) m= echanisms 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 b= e preferable:

1. Add a pair of sigils to enclose any expression t= hat would need to support userland operator overloading. This would allow a= developer to isolate just the expression that needs to use operator overlo= ading. I propose {[...]} for this, but feel free to bikeshed sigils. Using = an example from the RFC, here is what code might look like:

$cnum= 1 =3D new ComplexNumber(1, 2);
$cnum2 =3D new ComplexNumber(3, 4);
$cnum3 =3D {[ $cnum1 *= $cnum2 ]}; =C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2=A0=C2= =A0=C2=A0=C2=A0=C2=A0// Uses operator operloading sigils
echo $cnum3->realPart.= ' + '.$cnum3->imaginaryPart.'i';
=
2. For when u= sing `{[...]}` would be annoying because it would be needed in so many plac= es, 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 anyw= here in the body of the decorated structure. I included `Userland:true` as = an indicator to a reader that this only applies to userland operator overlo= ads 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 param= eters.

#[OperatorOverloads(Userland:true)]
function SprintProductOfTwoCo= mplex(ComplexNumber $cnum1, ComplexNumber $cnum2)string {
=C2=A0=C2=A0$cnum3 =3D= $cnum1 * $cnum2;
=C2=A0=C2=A0return sprintf("%d + %di", $cnum3->real= Part, $cnum3->imaginaryPart);
}

If this approach were included in the= RFC then it would also ensure there is no possibility of BC breakage. BC b= reakage which would certainly be an edge case but I can envision it would b= e possible,e specially where newer instances incorporating operator overloa= ds are passed to functions that did not have parameters type hinted but wer= e not intend to be used with operator overloads resulting in subtle potenti= al breakage.=C2=A0

This argument is also consistent = with the argument people had about not allowing default values to be generi= cally used in calls to the function function. Their claim was that develope= rs who did not write their code with the intention of exposing defaults sho= uld not have their defaults exposed. Similarly developers that do not write= their code to enable operator overloads should not be used with =C2=A0user= land operator overloads unless they explicitly allow it, especially as they= may not have have tested code with operator overloads.

Anyway, t= hat is my two cents worth.=C2=A0

TL;DR?=C2=A0 I argu= e that PHP should operator overloads but ONLY if there is a mechanism that = requires the user of expressions that call overloaded operators to explicit= ly opt-in to their use.

-Mike

<= /blockquote>

This is interesting, as I've never seen this in any language I res= earched as part of operator overloading, and also was never given this feed= back 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 opera= tors, 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 `Com= plexNumber` object. I presume in your example there that if the Attribute w= as removed, the function would just always produce a fatal error, since tha= t is the behavior of objects when used with `*`.

W= hat it appears to me your proposal does is transform working operator overl= oads into fatal errors if the user-code does not "opt-in". But an= y such code would never actually survive long, wouldn't it? Without the= opt-in, these objects would ALWAYS produce fatal errors (which is what hap= pens now), which would eventually show up in testing, QA, etc. The develope= r would realize that they (presumably) were trying to do a math operation o= n something they thought was only a numeric type, and then guard against ob= jects being passed into that context with control statements, parameter typ= es, etc.

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

What is the situation where yo= ur suggestion is implemented, a developer does NOT opt-in to overloads, and= they avoid unexpected behavior without having to change their existing cod= e 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 r= eference is not what I intended, however I want to highlight one other thin= g you commented there but not here for some reason:

>=20 To illustrate my point, imagine if we also allowed control structure=20 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 ambiguo= us after reading this, because I found it somewhat troubling:

=
I am looking at writing an RFC for specific *operators* that are finit= e 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 pos= sible without essentially rewriting the entire Zend Engine specifically to = do it).

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

Jordan
=C2=A0
--00000000000018479606224a1541--