Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:108805 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 77892 invoked from network); 2 Mar 2020 16:11:28 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 2 Mar 2020 16:11:28 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 9EA3B180089 for ; Mon, 2 Mar 2020 06:30:22 -0800 (PST) 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.1 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,FREEMAIL_FROM,HTML_MESSAGE, RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-lj1-f195.google.com (mail-lj1-f195.google.com [209.85.208.195]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Mon, 2 Mar 2020 06:30:22 -0800 (PST) Received: by mail-lj1-f195.google.com with SMTP id q23so12001507ljm.4 for ; Mon, 02 Mar 2020 06:30:22 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20161025; h=mime-version:references:in-reply-to:from:date:message-id:subject:to :cc; bh=OoOHSyR/gGyFEN3ieaW+70UWsMypnO5Xy6Hz4SpHti8=; b=A17RsKuX5cbpn1lvYXBaplfLVP3xC2Dd4ziNQTNVXSN4m4ScYE8oluBcuTue70qLpK llVcCKK6LslcUM+fjIqnuWUZTnE8Nb82QtMaKaWAwU5vvO2nG3fVuP5BAOthCAlaXbLP NH7LM2QO27VREY+pSM3aGJosPxSRP8lMIhOWeb/28ccs1sNuCvTqtMmHkuGV2+MWMBlM 85wgLNplCd/pysKzKEulXzAbtl/CRcMbknHALAq7GOSJx7bEkYugYZfyVKRSeBEDQmNd J0xH/rtG6K1NBAVIfTL5LykKCIb4b0Aj6n3CWDcg3DPqeED5Ex83mN2xgA15XkiJyVYi 1ZqQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:references:in-reply-to:from:date :message-id:subject:to:cc; bh=OoOHSyR/gGyFEN3ieaW+70UWsMypnO5Xy6Hz4SpHti8=; b=g1psofgI2zZ1mtsxu3ZxqoEPjPrx/k1yBIaTnU/Iv88izxwVj2T64on4I/nGA65HO1 rDzETtwtlVFF5JLVFifWTauROHJI5rCCRZYdgG4oaFcvLQcAmrNgNrQ/0cd+BDQo9QSh unz7dGJ87oHlcetU1bC38UD4yMw3KrY9aA+zU4wOJzhhg11icOO672sq2ZaYKNdYrFvz pCq9pKuKXOERpjUvqA4BUio2t5TLTujluQ0Dh3saIjKmqaVqThZ+TYvySyE4R+Tpuu81 2WN5EsHN9ibXetHgvkl+fYKT+EPMlKirstUXHbHkNM7nZVXXSyWql6qVs66m1eBBfmni CoaA== X-Gm-Message-State: ANhLgQ2MVdBPzkKtCihzqNCfAY4DKxYVFhySjWY8olbokJAOH0ng3Um7 gTvsnXWZXyAO4fve4B6hdwTEjaSHEPiZvXx3L20= X-Google-Smtp-Source: ADFU+vsXpgrNmMWv8e1PblRPpD3nVXCevR9T62U2qfqWYd4/JFHJR7sx9wlmVKkPwS7jvKjRXIH/gOnDBsL731ek1YU= X-Received: by 2002:a2e:9744:: with SMTP id f4mr12340727ljj.267.1583159419809; Mon, 02 Mar 2020 06:30:19 -0800 (PST) MIME-Version: 1.0 References: <005101d5edae$7b7c3e10$7274ba30$@gmx.de> In-Reply-To: <005101d5edae$7b7c3e10$7274ba30$@gmx.de> Date: Mon, 2 Mar 2020 15:30:03 +0100 Message-ID: To: jan.h.boehmer@gmx.de Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000d735a0059fe006ea" Subject: Re: [PHP-DEV] Re: [RFC] Userspace operator overloading From: nikita.ppv@gmail.com (Nikita Popov) --000000000000d735a0059fe006ea Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Thu, Feb 27, 2020 at 9:43 PM wrote: > On 15/02/2020 22:05, jan.h.boehmer@gmx.de wrote: > > Hi internals, > > > > based on the discussions here (https://externals.io/message/108300) and > here > > (https://github.com/php/php-src/pull/5156), I have created a proper RFC > for > > userspace operator overloading: > > https://wiki.php.net/rfc/userspace_operator_overloading > > > > The main differences to my original concept, is the removed __compare() > > method (comparison overloading is a complex topic and should be handled > in > a > > different RFC) and the possibility to signal that the operator handler > does > > not support the given types (by typehints or returning a special value)= . > > This way, only one of both objects has to know about the other type. Th= is > > should expand the use case of operator overloading compared to my old > > concept. > > > > What do you think about the RFC? > > > > Some discussion points, I can think of, would be the naming of the > methods > > (maybe naming them after the operator symbol and not the arithmetical > > operation they represent, e.g. __plus instead of __add) or putting the > > methods inside of interfaces like done for ArrayAccess (But I don=E2=80= =99t see > any > > advantage in doing so, as it is very difficult grouping different > operators > > in a single interface usefully. Also, operators can accept and return > > different types, so there is no real common interface between classes y= ou > > could rely on). > > Furthermore, maybe the idea of allowing operator overloading in general > > should be discussed as it is sometimes considered an anti-pattern (e.g. > the > > usage of '<<' for outputting a string in C++). On the other hand there > are > > many languages and libraries where operator overloading is used > successfully > > (e.g. numpy in Python). > > > > Regards, > > Jan B=C3=B6hmer > > I have changed the proposed names for the bitshift handlers to '__lshift' > and '__rshift' (instead of __sl and __sr) to make more clear what operato= r > is handled by the method (also the method names are now mostly consistent > with the Python equivalents). > > How many of you would prefer a interface solution for operator overloadin= g? > I wonder if the RFC voting should include the option to choose between > either the magic method approach (with the syntax proposed in the current > RFC version) or using interfaces. > For an interface version I would suggest these interfaces: > ArithmeticOperators (implements +, -, *, /), PowOperator (**), > ModuloOperator (%), ConcatOperator (.) and BitwiseOperators (~, &, |, ^, > <<, > >>). > What would be appropriate names for the interface methods? If we just nam= e > them after the operation (like add()), it will become difficult to > integrate > these interfaces into existing code, as add() is already a used function > name in many cases, but uses a different signature (non-static with one > argument, whereas the interface needs a static one with two arguments). > > Regards, > Jan > Some notes: Naming: If we're already going for more verbose names, I'd prefer __shiftLeft over __lshift. It may also make sense to use __bitwiseNot rather than __not, as it's currently not obviously whether it overloads the ~ or the ! operator. Similarly __bitwiseAnd could be better than __and, to make it clear that this is about & and not && or "and". Same for the other bitwise operators. > -$a is interpreted as (-1 * $a). As you mention this, for completeness: +$a is interpreted as (1 * $a). It may be worthwhile to give a more explicit list for a) operators that can be indirectly overloaded (and their desugaring) and b) operators that cannot be overloaded (like the boolean operators, comparison operators, instanceof, probably others). > If the operator handler function declares typehints (e.g. public static function __add(Vector3 $lhs, int $rhs)), the function handler is not called if the operand types do not match the signature, and the other operand's handler is tried to call. I'm somewhat skeptical about this. This smells of method overloading, and we don't do method overloading. There is no other place in PHP that would perform dispatching based on the method signature, even if in this case it's not a choice between multiple methods on the same class, but rather multiple methods on different classes. Some of the usual problems of method overloading don't apply here (in particular, one could make a reasonable argument that the method on the first object should be chosen, even if there is a more specific signature available on the second object), but I'm skeptical about introducing this kind of special case in the language specification. Regarding interfaces: I pretty strongly think that using interfaces for this purpose is not a good idea. Interfaces are about contracts, and there is no way (within the current limitations of PHP's type system) to define a useful contract here. I think others have already expanded on why it's not possible to group operators in a meaningful way. The DateTime example is probably the most pertinent there, in that DateTime + DateTime is illegal, while DateTime - DateTime is legal. If we can't even require both + and - as part of one interface, there is very little we can require. However, even if we split each method into it's own interface, what we'll be left with is something like interface Add { public static function add($a, $b); } What does this interface tell us? Pretty much nothing. It tells us that there probably exists at least one type with which this object can be added, but not what that type actually is or what the result type would be. There is no way to build code on the contract of "the object is addable with *something*". To make this useful, the interface would actually have to look something like this: interface Add { public static function add(T1 $a, T2 $b): T3; } and then DateTime would implement something like this: class DateTime implements Sub, Add { ... } That's a contract you could build code on, though it would be rather cumbersome. But in the absence of generic types, having an Add interface is not useful. The way I see operator overloading being used in PHP, I would expect code to be typed against specific classes, not supported operators. The vast majority of code will be interested in accepting a Money, not an Add. Regards, Nikita --000000000000d735a0059fe006ea--