Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125597 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 D4BA31A00BD for <internals@lists.php.net>; Tue, 17 Sep 2024 18:11:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1726596818; bh=o58SRvMXswsCNLgFXwnDH/GsvIsp2X6Xk0+GOJZd9EY=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=EwSt7cSy79S8Eldan7OuiTGaWPxfcH7SW1of+gsZiZg6GjK9URt8kPsQaUzahHNW8 oTeUoI9ML1DPBMKzm70Lp3KFeuIXCDcZ8kr0iEsnMdBcl/G8BVG8JP3T7kG7glKZ2Y Iiwvv4hRjXBje/W2r1mfywYDMpSP6F5zGlHWR///3iasweX8Lh+VO2ASdAgHIjWkYe iWggEfmCxXsrr2myCo6GMnqKcklnMsmhGfUMpajRSRXr3bs/MPLGTIFRNlB8Jvb6Jl nER2mpGTI7DEEBx08p9rQ4c9lYjUIZxTeoLcg8G9kwsTTpU1KFvZPvCw6y80EAkmvT zfGRZLPae1yBQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id B8D2818082C for <internals@lists.php.net>; Tue, 17 Sep 2024 18:13:33 +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: <jordan.ledoux@gmail.com> Received: from mail-pl1-f174.google.com (mail-pl1-f174.google.com [209.85.214.174]) (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 <internals@lists.php.net>; Tue, 17 Sep 2024 18:13:31 +0000 (UTC) Received: by mail-pl1-f174.google.com with SMTP id d9443c01a7336-206aee40676so36444275ad.0 for <internals@lists.php.net>; Tue, 17 Sep 2024 11:11:26 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1726596686; x=1727201486; 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=o58SRvMXswsCNLgFXwnDH/GsvIsp2X6Xk0+GOJZd9EY=; b=M7uKpM7ABuqnCq5yotuuNsx/nV6xgHzOFSTx1N0CzfssFVmOVINeM2jpCqVR8MNDNS 3cw+4Z0P0fhB3IOKptB3lvRatDyNOjwc4KiZFG+YpRQw/y4Jq/iak5pA8wNFfOn2qbpa b+B/IJ9wf7vXjkmscsZVgtfMLbKuMHhpkWz1ZsV1qbrvtgNPMdRLJ1t1cFihUoh8h3K/ YEWNvsMZbtk+sKf9nvHga/Dzah2yoT6PLsSIvJDJSD2Ax1SJ7bM+lkFjctLfZLv16HtZ TvtRAjqJTmUeVJRyewZ2LGv0d+GZDGio+iemEDsHVoi7u1C0OBhuBdTELvw61xLx2obO LA3g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726596686; x=1727201486; 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=o58SRvMXswsCNLgFXwnDH/GsvIsp2X6Xk0+GOJZd9EY=; b=RFu1cn+POc8xyJdLpwv8D7sKD+oOXG6r/8I+Ga2YvFMt41jHjbSXcTXYSq1xzv3nqq 9cSmqxPpG+FrmTeTmEMbm4nAHxPRlE2KiP9CCUwFZDPWyBC4uzDFRmjPN6aAdE1akBnU FdDLq2CCm87gnVf30A7YMDBVMMf3IePYuANpwPzV0TgFzTHUmPXa8VWfG6FpZNv080bB /NJRbikeyeiv9p5fmSU0SlREQTWbZP3+YNaFn6wD05m/rgC5/Aq8RuSrMQCNlA+Yr3LV SkIM0WiZNBqFhw4FtbscYqRqEVsvkZcYcY3JA/Iqt06kSfaSPSfghWUGqcwUbOM/lCWj n2VA== X-Forwarded-Encrypted: i=1; AJvYcCXe1U1NdeRgmDRVli98ikwE2eE6LloJqFwo4yMfMMqH7doSniMtgms8lbaSsTUt3Bj5Aq7Izo9p3Mw=@lists.php.net X-Gm-Message-State: AOJu0YzROaUuZJ42xsNJ8Ypao3oRekMoQj3WRdCkhdNvWJV9TY7GvgNP 0qY9pqQaBGN15SojRrqRrOdUxLfO4RkiMWtHDqWwq7lAzZNJbT2xFpirO89TU7kQ7Rl3Julo8Bh UUHq1XU/DBfjxJbkZoctSNI+tkmg= X-Google-Smtp-Source: AGHT+IGejWl3k3yScSFzFxIw8wZaWNPwLh8GLv60Dt7+gce33IQaRJGR+Oy8/d17DG+8N0Jhsw5whSp1DKebc0+YXuQ= X-Received: by 2002:a17:90b:33c4:b0:2d8:94f1:b572 with SMTP id 98e67ed59e1d1-2dbb9e1ce4fmr21061071a91.18.1726596685690; Tue, 17 Sep 2024 11:11:25 -0700 (PDT) Precedence: bulk list-help: <mailto:internals+help@lists.php.net list-unsubscribe: <mailto:internals+unsubscribe@lists.php.net> list-post: <mailto:internals@lists.php.net> List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: <CAMrTa2E2m00gOoGy5FbvkrLwM1AUP3ZmJXHkxh_R2qEszQ=NWA@mail.gmail.com> <2551c06a-ec1f-4870-a590-aeb5752fc944@rwec.co.uk> <CAMrTa2FLJwjwy9uGpRJJJFMUD1vs=vqzv8x2VxMsYeBqMN4m9Q@mail.gmail.com> <8C83F906-5B45-4CB9-8E6B-D85D43E74A63@daveyshafik.com> In-Reply-To: <8C83F906-5B45-4CB9-8E6B-D85D43E74A63@daveyshafik.com> Date: Tue, 17 Sep 2024 11:11:14 -0700 Message-ID: <CAMrTa2HWCpVZX-bUGLQtnvx0PredT4Zu0Qpkj3QfLLtpYq5f5Q@mail.gmail.com> Subject: Re: [PHP-DEV] [Pre-RFC Discussion] User Defined Operator Overloads (again) To: Davey Shafik <me@daveyshafik.com> Cc: "Rowan Tommins [IMSoP]" <imsop.php@rwec.co.uk>, internals@lists.php.net Content-Type: multipart/alternative; boundary="0000000000001efe9d0622549e91" From: jordan.ledoux@gmail.com (Jordan LeDoux) --0000000000001efe9d0622549e91 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Tue, Sep 17, 2024 at 10:55=E2=80=AFAM Davey Shafik <me@daveyshafik.com> = wrote: > > > On Sep 17, 2024, at 10:15, Jordan LeDoux <jordan.ledoux@gmail.com> wrote: > > > > On Tue, Sep 17, 2024 at 1:18=E2=80=AFAM Rowan Tommins [IMSoP] < > imsop.php@rwec.co.uk> wrote: > >> On 14/09/2024 22:48, Jordan LeDoux wrote: >> > >> > 1. Should the next version of this RFC use the `operator` keyword, or >> > should that approach be abandoned for something more familiar? Why do >> > you feel that way? >> > >> > 2. Should the capability to overload comparison operators be provided >> > in the same RFC, or would it be better to separate that into its own >> > RFC? Why do you feel that way? >> > >> > 3. Do you feel there were any glaring design weaknesses in the >> > previous RFC that should be addressed before it is re-proposed? >> > >> >> I think there are two fundamental decisions which inform a lot of the >> rest of the design: >> >> 1. Are we over-riding *operators* or *operations*? That is, is the user >> saying "this is what happens when you put a + symbol between two Foo >> objects", or "this is what happens when you add two Foo objects together= "? >> > > If we allow developers to define arbitrary code which is executed as a > result of an operator, we will always end up allowing the first one. > > >> 2. How do we despatch a binary operator to one of its operands? That is, >> given $a + $b, where $a and $b are objects of different classes, how do >> we choose which implementation to run? >> >> > This is something not many other people have been interested in so far, > but interestingly there is a lot of prior art on this question in other > languages! :) > > The best approach, from what I have seen and developer usage in other > languages, is somewhat complicated to follow, but I will do my best to ma= ke > sure it is understandable to anyone who happens to be following this thre= ad > on internals. > > The approach I plan to use for this question has a name: Polymorphic > Handler Resolution. The overload that is executed will be decided by the > following series of decisions: > > 1. Are both of the operands objects? If not, use the overload on the one > that is. (NOTE: if neither are objects, the new code will be bypassed > entirely, so I do not need to handle this case) > 2. If they are both objects, are they both instances of the same class? I= f > they are, use the overload of the one on the left. > 3. If they are not objects of the same class, is one of them a direct > descendant of the other? If so, use the overload of the descendant. > 4. If neither of them are direct descendants of the other, use the > overload of the object on the left. Does it produce a type error because = it > does not accept objects of the type in the other position? Return the err= or > and abort instead of re-trying by using the overload on the right. > > This results from what it means to `extend` a class. Suppose you have a > class `Foo` and a class `Bar` that extends `Foo`. If both `Foo` and `Bar` > implement an overload, that means `Bar` inherited an overload. It is eith= er > the same as the overload from `Foo`, in which case it shouldn't matter > which is executed, or it has been updated with even more specific logic > which is aware of the extra context that `Bar` provides, in which case we > want to execute the updated implementation. > > So the implementation on the left would almost always be executed, unless > the implementation on the right comes from a class that is a direct > descendant of the class on the left. > > `Foo + Bar` > `Bar + Foo` > > In practice, you would very rarely (if ever) use two classes from entirel= y > different class inheritance hierarchies in the same overload. That would > closely tie the two classes together in a way that most developers try to > avoid, because the implementation would need to be aware of how to handle > the classes it accepts as an argument. > > The exception to this that I can imagine is something like a container, > that maybe does not care what class the other object is because it doesn'= t > mutate it, only store it. > > But for virtually every real-world use case, executing the overload for > the child class regardless of its position would be preferred, because > overloads will tend to be confined to the core types of PHP + the classes > that are part of the hierarchy the overload is designed to interact with. > > >> >> >> Finally, a very quick note on the OperandPosition enum: I think just a >> "bool $isReversed" would be fine - the "natural" expansion of "$a+$b" is >> "$a->operator+($b, false)"; the "fallback" is "$b->operator+($a, true)" >> >> >> Regards, >> >> -- >> Rowan Tommins >> [IMSoP] >> > > This is similar to what I originally designed, and I actually moved to an > enum based on feedback. The argument was something like `$isReversed` or > `$left` or so on is somewhat ambiguous, while the enum makes it extremely > explicit. > > However, it's not a design detail I am committed to. I just want to let > you know why it was done that way. > > Jordan > > > To be clear: I=E2=80=99m very much in favor of operator overloading. I fr= equently > work with both Money value objects, and DateTime objects that I need to > manipulate through arithmetic with others of the same type. > > What if I wanted to create a generic `add($a, $b)` function, how would I > type hint the params to ensure that I only get =E2=80=9Caddable=E2=80=9D = things? I would > expect that to be: > > - Ints > - Floats > - Objects of classes with =E2=80=9Coperator+=E2=80=9D defined > > I think that an interface is the right solution for that, and you can jus= t > union with int/float type hints: add(int | float | Addable =E2=80=A6$oper= ands) (or > add(int | float | (Foo & Addable) =E2=80=A6$operands) > > Is this type of behavior even allowed? I think the intention is that it > must be otherwise the decision over which overload method gets called is > drastically simplified. > > Perhaps for a first iteration, operator overloads only work between > objects of the same type or their descendants =E2=80=94 and if a descenda= nt > overrides the overload, the descendants version is used regardless of > left/right precedence. > > I suspect this will simplify the complexity of the magic, and solve the > majority of cases where operator overloading is desired. > > - Davey > The problem with providing interfaces is something the nikic addressed very early in my design process and convinced me of: an `Addable` interface will not actually tell you if two objects can be added together. A `Money` class and a `Vector2D` class might both have an implementation for `operator +()` and implement some kind of `Addable` interface. But there is no sensible way in which they could actually be added. Knowing that an object implements an overload is not enough in most cases to use operators with them. This is part of the reason that I am skeptical of people who worry about accidentally using random overloads. The signature for the implementation in the `Money` class, might look something like this: `operator +(Money $other, OperandPosition $position): Money` while the signature for the implementation in the `Vector2D` class might look something like this: `operator +(Vector2D|array $other, OperandPosition $position): Vector2D` Any attempt to add these two together will result in a `TypeError`. Classes which have overloads that look like the following would be something I think developers should be IMMEDIATELY suspicious of: `operator +(object $other, OperandPosition $position)` `operator +(mixed $other, OperandPosition $position)` Does your implementation really have a plan for how to `+` with a stream resource like a file handler, as well as an int? Can you just as easily use `+` with the `DateTime` class as you can with a `Money` class in your implementation? I think there are very few use cases that would survive code reviews or feedback or testing that look like any of these signatures. There are situations in which objects might accept objects from a different class hierarchy. For instance, with the changes Saki has made there are now objects for numbers in the BcMath extension. Those are objects that might be quite widely accepted in overload implementations, since they represent numbers in the same way that just an int or float might. But I highly doubt that it's even possible for the overload to accept those sorts of things without also being aware of them, and if the overload is aware of them it can type-hint them in the signature. Jordan --0000000000001efe9d0622549e91 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div dir=3D"ltr"><br></div><br><div class=3D"gmail_quote">= <div dir=3D"ltr" class=3D"gmail_attr">On Tue, Sep 17, 2024 at 10:55=E2=80= =AFAM Davey Shafik <<a href=3D"mailto:me@daveyshafik.com">me@daveyshafik= .com</a>> wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"mar= gin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1= ex"><div><br id=3D"m_-8993855455494056280lineBreakAtBeginningOfMessage"><di= v><br><blockquote type=3D"cite"><div>On Sep 17, 2024, at 10:15, Jordan LeDo= ux <<a href=3D"mailto:jordan.ledoux@gmail.com" target=3D"_blank">jordan.= ledoux@gmail.com</a>> wrote:</div><br><div><br><br style=3D"font-family:= Helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-we= ight:400;letter-spacing:normal;text-align:start;text-indent:0px;text-transf= orm:none;white-space:normal;word-spacing:0px;text-decoration:none"><div cla= ss=3D"gmail_quote" style=3D"font-family:Helvetica;font-size:12px;font-style= :normal;font-variant-caps:normal;font-weight:400;letter-spacing:normal;text= -align:start;text-indent:0px;text-transform:none;white-space:normal;word-sp= acing:0px;text-decoration:none"><div dir=3D"ltr" class=3D"gmail_attr">On Tu= e, Sep 17, 2024 at 1:18=E2=80=AFAM Rowan Tommins [IMSoP] <<a href=3D"mai= lto:imsop.php@rwec.co.uk" target=3D"_blank">imsop.php@rwec.co.uk</a>> wr= ote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px= 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 14/09/20= 24 22:48, Jordan LeDoux wrote:<br>><br>> 1. Should the next version o= f this RFC use the `operator` keyword, or<span>=C2=A0</span><br>> should= that approach be abandoned for something more familiar? Why do<span>=C2=A0= </span><br>> you feel that way?<br>><br>> 2. Should the capability= to overload comparison operators be provided<span>=C2=A0</span><br>> in= the same RFC, or would it be better to separate that into its own<span>=C2= =A0</span><br>> RFC? Why do you feel that way?<br>><br>> 3. Do you= feel there were any glaring design weaknesses in the<span>=C2=A0</span><br= >> previous RFC that should be addressed before it is re-proposed?<br>&g= t;<br><br>I think there are two fundamental decisions which inform a lot of= the<span>=C2=A0</span><br>rest of the design:<br><br>1. Are we over-riding= *operators* or *operations*? That is, is the user<span>=C2=A0</span><br>sa= ying "this is what happens when you put a + symbol between two Foo<spa= n>=C2=A0</span><br>objects", or "this is what happens when you ad= d two Foo objects together"?<br></blockquote><div><br></div><div>If we= allow developers to define arbitrary code which is executed as a result of= an operator, we will always end up allowing the first one.<br></div><div>= =C2=A0</div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0= .8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">2. How do we = despatch a binary operator to one of its operands? That is,<span>=C2=A0</sp= an><br>given $a + $b, where $a and $b are objects of different classes, how= do<span>=C2=A0</span><br>we choose which implementation to run?<br><br></b= lockquote><div><br></div><div>This is something not many other people have = been interested in so far, but interestingly there is a lot of prior art on= this question in other languages! :)<span>=C2=A0</span><br></div><div><br>= </div><div>The best approach, from what I have seen and developer usage in = other languages, is somewhat complicated to follow, but I will do my best t= o make sure it is understandable to anyone who happens to be following this= thread on internals.</div><div><br></div><div>The approach I plan to use f= or this question has a name: Polymorphic Handler Resolution. The overload t= hat is executed will be decided by the following series of decisions:</div>= <div><br></div><div>1. Are both of the operands objects? If not, use the ov= erload on the one that is. (NOTE: if neither are objects, the new code will= be bypassed entirely, so I do not need to handle this case)</div><div>2. I= f they are both objects, are they both instances of the same class? If they= are, use the overload of the one on the left.</div><div>3. If they are not= objects of the same class, is one of them a direct descendant of the other= ? If so, use the overload of the descendant.</div><div>4. If neither of the= m are direct descendants of the other, use the overload of the object on th= e left. Does it produce a type error because it does not accept objects of = the type in the other position? Return the error and abort instead of re-tr= ying by using the overload on the right.</div><div><br></div><div>This resu= lts from what it means to `extend` a class. Suppose you have a class `Foo` = and a class `Bar` that extends `Foo`. If both `Foo` and `Bar` implement an = overload, that means `Bar` inherited an overload. It is either the same as = the overload from `Foo`, in which case it shouldn't matter which is exe= cuted, or it has been updated with even more specific logic which is aware = of the extra context that `Bar` provides, in which case we want to execute = the updated implementation.</div><div><br></div><div>So the implementation = on the left would almost always be executed, unless the implementation on t= he right comes from a class that is a direct descendant of the class on the= left.</div><div><br></div><div>`Foo + Bar`</div><div>`Bar + Foo`<br></div>= <div><br></div><div>In practice, you would very rarely (if ever) use two cl= asses from entirely different class inheritance hierarchies in the same ove= rload. That would closely tie the two classes together in a way that most d= evelopers try to avoid, because the implementation would need to be aware o= f how to handle the classes it accepts as an argument.</div><div><br></div>= <div>The exception to this that I can imagine is something like a container= , that maybe does not care what class the other object is because it doesn&= #39;t mutate it, only store it.</div><div><br></div><div>But for virtually = every real-world use case, executing the overload for the child class regar= dless of its position would be preferred, because overloads will tend to be= confined to the core types of PHP + the classes that are part of the hiera= rchy the overload is designed to interact with.<br></div><div>=C2=A0</div><= blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-l= eft:1px solid rgb(204,204,204);padding-left:1ex"><br><br>Finally, a very qu= ick note on the OperandPosition enum: I think just a<span>=C2=A0</span><br>= "bool $isReversed" would be fine - the "natural" expans= ion of "$a+$b" is<span>=C2=A0</span><br>"$a->operator+($b= , false)"; the "fallback" is "$b->operator+($a, true= )"<br><br><br>Regards,<br><br>--<span>=C2=A0</span><br>Rowan Tommins<b= r>[IMSoP]<br></blockquote><div><br></div><div>This is similar to what I ori= ginally designed, and I actually moved to an enum based on feedback. The ar= gument was something like `$isReversed` or `$left` or so on is somewhat amb= iguous, while the enum makes it extremely explicit.</div><div><br></div><di= v>However, it's not a design detail I am committed to. I just want to l= et you know why it was done that way.</div><div><br></div><div>Jordan</div>= </div></div></blockquote><br></div><div>To be clear: I=E2=80=99m very much = in favor of operator overloading. I frequently work with both Money value o= bjects, and DateTime objects that I need to manipulate through arithmetic w= ith others of the same type.</div><div><br></div><div>What if I wanted to c= reate a generic `add($a, $b)` function, how would I type hint the params to= ensure that I only get =E2=80=9Caddable=E2=80=9D things? I would expect th= at to be:</div><div><br></div><div>- Ints</div><div>- Floats</div><div>- Ob= jects of classes with =E2=80=9Coperator+=E2=80=9D defined</div><div><br></d= iv><div>I think that an interface is the right solution for that, and you c= an just union with int/float type hints: add(int | float | Addable =E2=80= =A6$operands) (or add(int | float | (Foo & Addable) =E2=80=A6$operands)= </div><div><br></div><div>Is this type of behavior even allowed? I think th= e intention is that it must be otherwise the decision over which overload m= ethod gets called is drastically simplified.</div><div><br></div><div>Perha= ps for a first iteration, operator overloads only work between objects of t= he same type or their descendants =E2=80=94 and if a descendant overrides t= he overload, the descendants version is used regardless of left/right prece= dence.</div><br><div>I suspect this will simplify the complexity of the mag= ic, and solve the majority of cases where operator overloading is desired.<= /div><div><br></div><div>- Davey</div></div></blockquote><div><br></div><di= v>The problem with providing interfaces is something the nikic addressed ve= ry early in my design process and convinced me of: an `Addable` interface w= ill not actually tell you if two objects can be added together. A `Money` c= lass and a `Vector2D` class might both have an implementation for `operator= =C2=A0+()` and implement some kind of `Addable` interface. But there is no = sensible way in which they could actually be added. Knowing that an object = implements an overload is not enough in most cases to use operators with th= em. This is part of the reason that I am skeptical of people who worry abou= t accidentally using random overloads.</div><div><br></div><div>The signatu= re for the implementation in the `Money` class, might look something like t= his:</div><div><br></div><div>`operator +(Money $other, OperandPosition $po= sition): Money`</div><div><br></div><div>while the signature for the implem= entation in the `Vector2D` class might look something like this:</div><div>= <br></div><div>`operator +(Vector2D|array $other, OperandPosition $position= ): Vector2D`</div><div><br></div><div>Any attempt to add these two together= will result in a `TypeError`.</div><div><br></div><div>Classes which have = overloads that look like the following would be something I think developer= s should be IMMEDIATELY suspicious of:</div><div><br></div><div>`operator += (object $other, OperandPosition $position)`</div><div>`operator +(mixed $ot= her, OperandPosition $position)`</div><div><br></div><div>Does your impleme= ntation really have a plan for how to `+` with a stream resource like a fil= e handler, as well as an int? Can you just as easily use `+` with the `Date= Time` class as you can with a `Money` class in your implementation?</div><d= iv><br></div><div>I think there are very few use cases that would survive c= ode reviews or feedback or testing that look like any of these signatures.<= /div><div><br></div><div>There are situations in which objects might accept= objects from a different class hierarchy. For instance, with the changes S= aki has made there are now objects for numbers in the BcMath extension. Tho= se are objects that might be quite widely accepted in overload implementati= ons, since they represent numbers in the same way that just an int or float= might. But I highly doubt that it's even possible for the overload to = accept those sorts of things without also being aware of them, and if the o= verload is aware of them it can type-hint them in the signature.<br></div><= div><br></div><div>Jordan<br></div></div></div> --0000000000001efe9d0622549e91--