Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:108968 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 1057 invoked from network); 11 Mar 2020 11:01:17 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 11 Mar 2020 11:01:17 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3E2A318050A for ; Wed, 11 Mar 2020 02:22:22 -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.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-f179.google.com (mail-lj1-f179.google.com [209.85.208.179]) (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 ; Wed, 11 Mar 2020 02:22:21 -0700 (PDT) Received: by mail-lj1-f179.google.com with SMTP id w1so1479672ljh.5 for ; Wed, 11 Mar 2020 02:22:21 -0700 (PDT) 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=AKgJDBnI8PiCfDF8j5rc8Huer1+jMPPox7CILJ5JUco=; b=gQKsawjSnbrljAEu7UKA9JtZGm9vlHlNpltN9D/6HMYZZStB6hXQfdEEKsAfLDljss NtB8LMHuhpe4f1fS4+rxDPf1apFoChGQq7Vyv8hj/eAozlIOxpV2Ck/KlLE4Adyn9tbb pSTsWs6fpdD7UhD3GEYmsNZaF+s6x6++ObzUA+LtDdmrdmewkCnt7eSSJu/EV95QQIra 8QzYfS3gtOBGu/cpmaUyY+Fx/LLyMeY+23YThdGZf8gUdTT0SuhA6hdgmJEBonPk4+oK gAwJeBXt5GrDR9urrhB/2pL6PKdzvR24RfYB8B085PJ38oMnfYuekXWexRpB39gOHDHX elMQ== 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=AKgJDBnI8PiCfDF8j5rc8Huer1+jMPPox7CILJ5JUco=; b=BHF6mqE8tuTyMmKaqfak4xI97XhU6TmEbKzUpE7rlKAX6dG9C1FwS0MB6nFnDI8okR a2f6Jlv51cetSiQ3yoRX0BJM0HMKgenMr9Ukv5QfPwUsUyPfG1hPCpkwUq5w+GDGi8Zw FMtfM+EHVw8BdmaNrpKb372TIAHUEUPutWxWhnLwcia/YsLAIs+YpshlLUO5mKp2aby4 t4uky6afNJBKdxznxu7SxdxkQVd/HZhh0nuAFAC3k8VzQJuJcbYN/zJC5GYKIfMkf07C Uvyl2ghebSWO7i8bLkDi+WY1e5k2f4/jsrQywhcijT33Wr51iQlX25dQJxV5tF5jCb1M G6lw== X-Gm-Message-State: ANhLgQ1yLxMRHWRbYRM+AVh8exsDEyuJ3CoygxlDA9TrXhfEIn6zV5dF oXTVg+bqgPEvNYD62iOYDtTySaXPHPxXbmIAZ2g= X-Google-Smtp-Source: ADFU+vsRzg9bpFeI4h0/Bk7/936idqO1jQXwLuCMERwZlIBt55wWw+voLfFDQ35EGDD7dZKcdFHifTxoDU4nKt4t2HQ= X-Received: by 2002:a2e:86d0:: with SMTP id n16mr1552252ljj.117.1583918539401; Wed, 11 Mar 2020 02:22:19 -0700 (PDT) MIME-Version: 1.0 References: <005101d5edae$7b7c3e10$7274ba30$@gmx.de> <8776962f-71ac-0ee3-a1b8-42eb2926eef0@gmx.de> In-Reply-To: <8776962f-71ac-0ee3-a1b8-42eb2926eef0@gmx.de> Date: Wed, 11 Mar 2020 10:22:03 +0100 Message-ID: To: =?UTF-8?Q?Jan_B=C3=B6hmer?= Cc: PHP internals Content-Type: multipart/alternative; boundary="000000000000e4ed4905a090c52d" Subject: Re: [PHP-DEV] Re: [RFC] Userspace operator overloading From: nikita.ppv@gmail.com (Nikita Popov) --000000000000e4ed4905a090c52d Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Mar 6, 2020 at 9:17 AM Jan B=C3=B6hmer wrote= : > Am 02.03.2020 um 15:30 schrieb Nikita Popov: > > 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) an= d >> here >> > (https://github.com/php/php-src/pull/5156), I have created a proper RF= C >> 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 handle= d >> 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. >> This >> > 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 >> you >> > could rely on). >> > Furthermore, maybe the idea of allowing operator overloading in genera= l >> > 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 operat= or >> is handled by the method (also the method names are now mostly consisten= t >> with the Python equivalents). >> >> How many of you would prefer a interface solution for operator >> overloading? >> I wonder if the RFC voting should include the option to choose between >> either the magic method approach (with the syntax proposed in the curren= t >> 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 na= me >> 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 t= he > ~ or the ! operator. Similarly __bitwiseAnd could be better than __and, t= o > make it clear that this is about & and not && or "and". Same for the othe= r > 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 call= ed > 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 meth= od > 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 ther= e > 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 b= e. > 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 > > I have changed the names of the handlers like you suggested and added two > tables which show what operators can be overloaded indirectly and which c= an > not be overloaded at all. Thank you for your suggestion. > > I agree with your opinion with on interfaces, I think using magic methods > is much more reasonable. > > Your point about the "smell of method overloading" is interesting. In my > opinion this mechanism makes it a bit easier to use operator overloading = as > you dont have to do tedious typecheckings on your own in simple cases. Bu= t > I agree that this behavior is a bit odd compared to other PHP features. > > That feature is not really needed for operator overloading, as you can us= e > the PHP_UNKNOWN_OPERAND_TYPES const for signaling that the handler does n= ot > support the given types. If you (the internals developers) says that this > does not fit into the concept of PHP, I will remove it from my RFC (or pu= t > it in a separate votation, if wished). > Does anyone else have thoughts on the ability to specify the supported types in the signature? Nikita --000000000000e4ed4905a090c52d--