Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:109585 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 18113 invoked from network); 9 Apr 2020 20:29:37 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 9 Apr 2020 20:29:37 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id E48211804C3 for ; Thu, 9 Apr 2020 11:58:06 -0700 (PDT) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-2.6 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_LOW,SPF_HELO_PASS,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS11403 64.147.123.0/24 X-Spam-Virus: No X-Envelope-From: Received: from wout3-smtp.messagingengine.com (wout3-smtp.messagingengine.com [64.147.123.19]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 9 Apr 2020 11:58:06 -0700 (PDT) Received: from compute7.internal (compute7.nyi.internal [10.202.2.47]) by mailout.west.internal (Postfix) with ESMTP id 10E0B872 for ; Thu, 9 Apr 2020 14:58:05 -0400 (EDT) Received: from imap26 ([10.202.2.76]) by compute7.internal (MEProxy); Thu, 09 Apr 2020 14:58:05 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d= messagingengine.com; h=content-type:date:from:in-reply-to :message-id:mime-version:references:subject:to:x-me-proxy :x-me-proxy:x-me-sender:x-me-sender:x-sasl-enc; s=fm2; bh=4GZzhx Vz0xFZBXdIcgByZd4qM22F5vfkHjoj7WB3xdU=; b=bUSS0WdDCmuk61iWHkA9ax oHmW7WzR4ajU1+sLhjAoqg+zRkgqpcXGEOHIlOjl+MY9CUVf2zw9goQV025dVAcH jCV696d7jpaRvySQSu1raG3SinYfwIrKNM9poWFpYflakiLk8jcPY5nYuNe31Cod YtelD2CVRumqXinh5FZbC9n948QttDSnZu738aIJYjdb1SDYhQmQp0NOcZ3VoVkf kbKNXxoIRqZJaVb5PbpmBTm0R11aap7TlDvK4I5ZD7V7NQa3FRM6fi1+TInH6LQJ R90WYjMCO7piPzKKb84DechBW+N4MfbPWiObij3djny5uY122HaFkmwV0eeShc9Q == X-ME-Sender: X-ME-Proxy-Cause: gggruggvucftvghtrhhoucdtuddrgeduhedrudelgdduvdeiucetufdoteggodetrfdotf fvucfrrhhofhhilhgvmecuhfgrshhtofgrihhlpdfqfgfvpdfurfetoffkrfgpnffqhgen uceurghilhhouhhtmecufedttdenucesvcftvggtihhpihgvnhhtshculddquddttddmne cujfgurhepofgfggfkjghffffhvffutgesthdtredtreertdenucfhrhhomhepfdfnrghr rhihucfirghrfhhivghlugdfuceolhgrrhhrhiesghgrrhhfihgvlhguthgvtghhrdgtoh hmqeenucevlhhushhtvghrufhiiigvpedtnecurfgrrhgrmhepmhgrihhlfhhrohhmpehl rghrrhihsehgrghrfhhivghlughtvggthhdrtghomh X-ME-Proxy: Received: by mailuser.nyi.internal (Postfix, from userid 501) id 393E414200A2; Thu, 9 Apr 2020 14:58:04 -0400 (EDT) X-Mailer: MessagingEngine.com Webmail Interface User-Agent: Cyrus-JMAP/3.1.7-1104-g203475c-fmstable-20200408v2 Mime-Version: 1.0 Message-ID: <043256e2-08f3-4e43-9bd3-fb767a828e09@www.fastmail.com> In-Reply-To: References: <003701d6013c$9afe9750$d0fbc5f0$@gmx.de> <7a83f950a31d94d5ff2307ac8219db3b7b6482b6.camel@schlueters.de> <12ad7c71-8958-7742-12c4-e83e359c8186@gmx.de> <3B71F74D-8142-48FB-9660-835B08D1DDDD@schlueters.de> <705aba69-8c17-f882-19fd-6f41a2c2ca25@gmx.de> <07f176a5c2ff0338cb67c9755bf37af6dcc2d465.camel@schlueters.de> <000d01d60c4a$a213fb20$e63bf160$@gmx.de> Date: Thu, 09 Apr 2020 13:57:43 -0500 To: "php internals" Content-Type: text/plain Subject: Re: [PHP-DEV] [VOTE] Userspace operator overloading From: larry@garfieldtech.com ("Larry Garfield") On Thu, Apr 9, 2020, at 10:05 AM, Rowan Tommins wrote: > On Thu, 9 Apr 2020 at 13:18 (and subsequent correction), Dan Ackroyd < > Danack@basereality.com> wrote: > > > > $a = new A; > > > $b = new B; > > > var_dump($b + $a); # calls B::__add($b, $a); OK > > > var_dump($a + $b); # calls A::__add($a, $b), which is a TypeError > > > > > > ... that code does have a TypeError. It is > > calling '__add' and passing a parameter to the method that the code > > can't handle. > > > > It appears to be the same error case as: > > > > ``` > > class A { > > public function add(A $rhs) {...} > > } > > > > class B { > > public function add(A|B $rhs) {...} > > } > > > > $a = new A; > > $b = new B; > > > > $b->add($a); // Ok > > $a->add($b); // TypeError > > ``` > > > > > As with so much else on this topic, it depends how you think about operator > overloading - and I think that's why it's so hard to agree on an > implementation. > > It seems that you're picturing the overloaded + as like a normal method but > with special syntax, so that $a + $b means the same as $a->add($b) and only > that. In that interpretation, it's perfectly reasonable to have the > operation succeed or fail based only on the left-hand operand, because > that's how we're used to method dispatch working. > > But if you look at how "normal" operators work, it's far less obvious that > the order of operands should play any role in that decision. For instance, > when mixing float and int, the result is a float if *either* of the > operands is a float: > > var_dump(1 + 1); # int(2) > var_dump(1 + 1.0); # float(2) > var_dump(1.0 + 1); # float(2) > var_dump(1.0 + 1.0); # float(2) > > Substitute 1 for $a and 1.0 for $b, and you're back to the example I > originally wrote. Note that this is true even for non-commutative operators > like exponentiation: > > var_dump(2 ** 3); # int(8) > var_dump(2 ** 3.0); # float(8) > var_dump(2.0 ** 3); # float(8) > var_dump(2.0 ** 3.0); # float(8) > > My impression is what people consider "good" use of operator overloading is > much closer to "make things act like built in numerics" than "make > operators with fancy syntax", so some form of symmetry is necessary I think. > > Regards, > -- > Rowan Tommins > [IMSoP] Idle, possibly naive thought: When applying operator overloading to objects, perhaps we could simplify matters by insisting that it only work for directly compatible types? That is: class Foo { public function __add(Foo $b): Foo { return new FooOrChildOfFood(); } } It would work for interfaces too, but the point is that you *can't* operate on just any old other value... only one that is of the same type. You could technically have a BarInterface, and then only the left-side object gets called, but it means it has to be combining two BarInterface objects, which means it knows how, because BarInterface has the necessary methods. If not, then your BarInterface is wrong and you should feel bad. This creates a narrower use case, but perhaps one that still fits the practical usage patterns? (Eg, adding Money objects together, etc.) If an operator by design wants different types on each side (not for numeric behavior, but for, eg, a function concatenation operator), then you would have to type the RHS you expect (eg, a callable in that case). It's not as extensible, but the extensibility seems like it's the problem in the first place. I generally agree with those who have said that any such functionality needs to leverage the type system effectively, not side-step it. As I said, possibly naive thought, but could deliberately reducing the scope make life simpler? --Larry Garfield