Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:115681 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 99230 invoked from network); 10 Aug 2021 06:45:15 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 10 Aug 2021 06:45:15 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 4F8DE180504 for ; Tue, 10 Aug 2021 00:15:39 -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=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_NONE 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-qt1-f173.google.com (mail-qt1-f173.google.com [209.85.160.173]) (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 ; Tue, 10 Aug 2021 00:15:38 -0700 (PDT) Received: by mail-qt1-f173.google.com with SMTP id a12so14735870qtb.2 for ; Tue, 10 Aug 2021 00:15:38 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20150623.gappssmtp.com; s=20150623; h=mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=u8Qse24D17K30fAae2E++obDKZR3Csny0tstFlxp1HY=; b=kQSqRxClKsnX75tugapUwkPAU2nEQjVp0Uz5ZljHZ4Fq75Jzj28IU9dGGz96MzhT6S zZq5XPC+3kjJHJIiRIJ+RjzvTSU6yTcHtXNSzTxKxQy6Hq6YE+qMOFrEYDg6ODWH0O8H 9vsc0KTtOb+hcYO/bhnG9IK73P+G2dwvqKOloYvY1ZaOnDChijDWx2TZVUUU+worwoXq kNt5ELcw4H/AdAveLyHzBMMniLZd3qQ3Vz7XmpKQL7Yacz6asazyz1ZcWFleES4LAHdh ItOfRHlgIML3jGQ5ufLcywWcYG0keNVFTslrYx0gVGgZe1F3bqY8LFPvdo++bZ7RCWkf hYDg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=u8Qse24D17K30fAae2E++obDKZR3Csny0tstFlxp1HY=; b=T2FqquDLDGoc3+C8cQcRNZbPXq82OyxtTFu9nVHDD4YwreRfiLfAbz7hmC421CTY8h elZLfSqlfHNCLTYZpt06nGOnTUnaDOfb7WSA22s8ieU3uE+WXPwcHwk+ZA/IIrBIGdEV LgEBUNmVVUSYePcWN8/XflMFYJZCdKMuQTiiIc1/b5DWaeLTkfuJIaEgehVTihML0uA+ W3YAnSixemlX9Qo9pvd4YcNiEh48mY83UtWAFdxIENrfzydgoikQ1XxtlO9ujyHrvc4D ewYeFveJc6ADg7cOcbuPfSlm6XBvyWFkCdEq+Wi5TW4Z2Hz2jTdZDWH2BNi5mhnx84o4 B2wA== X-Gm-Message-State: AOAM532kF7eDJ0RJNFqL7iVTaPYwrp/bWDjW+wpDbu80OXB3ZgPEqndo 3yG6BCwtFS9zEbLjerhDKKIlPg== X-Google-Smtp-Source: ABdhPJzS2I1hSKcv1YZ4JNL8b6tNG6pVKilS8QUMeN979zTJpr8z2EST5vTLyrXfT5FeD8d4MBLRDQ== X-Received: by 2002:ac8:5dd1:: with SMTP id e17mr23886650qtx.270.1628579737792; Tue, 10 Aug 2021 00:15:37 -0700 (PDT) Received: from [192.168.1.10] (c-24-98-254-8.hsd1.ga.comcast.net. [24.98.254.8]) by smtp.gmail.com with ESMTPSA id y11sm3150773qtx.13.2021.08.10.00.15.36 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 10 Aug 2021 00:15:36 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 13.4 \(3608.120.23.2.7\)) In-Reply-To: Date: Tue, 10 Aug 2021 02:51:47 -0400 Cc: php internals Content-Transfer-Encoding: quoted-printable Message-ID: References: <94696d46-c4e6-406a-b859-89144bff31bf@www.fastmail.com> To: Jordan LeDoux X-Mailer: Apple Mail (2.3608.120.23.2.7) Subject: Re: [PHP-DEV] Revisiting Userland Operator Overloads From: mike@newclarity.net (Mike Schinkel) > On Aug 9, 2021, at 8:40 PM, Jordan LeDoux = wrote: > That is in part of why I asked for use-case examples, to see if there = really were a lot of use-cases where operator overloading makes sense. = You only provided two categories; Math and the already existing = DateInterval.=20 >=20 > This seems... a bit reductionist? I suppose if you consider anything = that has a numeric value "math", then sure.=20 I can see how you might have interpreted my reference to Math as "all = math." =20 However, I was only referring to the explicit list you provided. Again, = for reference: Math ------------ - Complex number objects - Fractions objects - Matrix objects (math) - Vector objects (math) - Arbitrary precision numbers (which are usually represented as a string = in PHP) > Math is extremely large. Geometry is very different from matrices, = which is very different from arithmetic, which is very different from = complex numbers. So that gives me two (2) thoughts 1.) First is Geometry would be another area for PHP to consider adding = classes. 2.) Then I thought: What if PHP had the ability to explicitly define = *value* objects? I know this has been something Larry Garfield has = mentioned[1] in the past. =20 What if we had a new type of class that is to be used only for value = objects. Following Larry's lead they would be immutable. And if we had = those then I think adding generic operators overloading to value objects = would make a hell of a lot of sense. Maybe: #[\PHP\Value] class ComplexNumber{} Or: class ComplexNumber value{} Or: ??? Can you see any reason why only allowing the addition of operator = overloads to *value* objects would too limiting?=20 IMO that would minimize the abuse potential for implementing operators = as a leaky abstraction when developers are ignorant of the ramifications = and/or are more concerning about their convenience than longer term = maintainability.=20 [1] https://twitter.com/Crell/status/621715583403487232 > Again, I'm providing those examples because I can literally bring up = code from my own libraries for those, so I'm a good advocate for them. = But others certainly exist. I think you would throw this under "math", = but what about unit-based values? If you wanted to do `19cm + 2m`, you = could return `219cm`, or `2.19m`, or `2190mm`. Supposing that there was = an abstract, how would it know what unit conversion to use? Or what = about `2km + 4mi`? Or what about erroring for `2km + 4L`? Length is a really great example, thanks for bringing it up. =20 According to NIST there are seven (7) base units[2] where "Definitions = of all seven (7) SI base units are expressed using an explicit-constant = formulation and experimentally realized using a specific mises en = pratique (practical technique)." =20 This means they are well-known and unlikely have changing requirements. = They are: =E2=80=A2 Length e.g. meters =E2=80=A2 Time e.g. seconds =E2=80=A2 Amount of substance e.g. moles =E2=80=A2 Electric current e.g. amperes =E2=80=A2 Temperature e.g. kelvin =E2=80=A2 Luminous intensity e.g. candela =E2=80=A2 Mass e.g. kilogram Those seem like a great *finite* list of fundamental units I would argue = PHP could benefit userland developers greatly by adding *standardized* = classes to handle them, maybe in a `PHP\Units` namespace. We already = have Time. Then I can envision a `Value` base class, trait(s) and/or interfaces = that could support generic unit conversion that these specific units, = like Length. 1 'm' could be defined equal to 100 'cm' and then this = could be possible: use PHP\Units\Length; $length =3D (new Length(19,'cm')) + (new Length(2,'m')); echo $length->toCentimeters(); // prints 219 echo $length->toMeters(); // prints 2.19=20 echo $length->toMillimeters(); // prints 2190 $length =3D (new Length(2,'km')) + (new Length(4,'mi')); echo $length->toMiles(); // prints 5.24274 echo $length->toKilometers(); // prints 8.43736 Then something like this could also be valid, and be what the above is = actually built on: use PHP\Units\Units; use PHP\Units\Value; $units =3D new Units(); $units->addUnit('m','Meter'); $units->addUnit('cm','Centimeter'); $units->addUnit('mm', 'Millimeters'); $units->addConversion('cm','m',100); $units->addConversion('mm','m',1000); $length =3D (new Value(19,'cm',$units)) + (new Value(2,'m',$units)); echo $length->toUnit('cm'); // prints 219 echo $length->toUnit('m'); // prints 2.19=20 echo $length->toUnit('mm'); // prints 2190 $units->addConversion('m','km',1000); $units->addConversion('mi','km',1.60934); $units->addUnit('km', 'Kilometers'); $units->addUnit('mi','Miles'); $length =3D (new Length(2,'km',$units)) + (new Length(4,'mi',$units)); echo $length->toUnit('km'); // prints 5.24274 echo $length->toUnit('mi'); // prints 8.43736 We could even open up the discussion of having scalar literals for these = types, e.g. where `2m` is a 2 meter value object of type Length. Note that having value objects and having these seven units of measure = added to PHP need not be mutually exclusive. As an aside, if you take 10 developers and ask them to create a = ComplexNumber class you will almost certainly get 10 different, unique = implementations. However, if a ComplexNumber class is added to a = language there is a good chance all 10 developers would just use it and = not rebel against it. That is not always the case =E2=80=94 look at the = SPL =E2=80=94 but while most people may grumble about the string = functions they all still use them. And same for the DateTime and = DateInterval classes. I expect the same would be true for a Length = class, et.al. [2] https://www.nist.gov/pml/weights-and-measures/metric-si/si-units > Another good example of unit based values would be online stores = controlling inventory and carts. You could have item ID's be the 'unit' = to control them, or perhaps you 'unit' them by their shipping size. Or = perhaps store items actually have several units attached to them, so = that you could automatically combine shipping volumes and weights, while = in other locations combining quantities and prices.=20 And that IMO is an example where operator overloading could end up being = a leaky abstraction where different developers would have different = conceptions for what each unit should be. > All of these things are *possible* in PHP. This doesn't enable those = things. But it makes them cleaner and easier to reason about, and = reduces the code necessary to accomplish them. I'd argue for the shopping cart example it would make it more difficult = to reason about for the very reason that you gave three different = potentials for how to define a unit. As for Length being appropriate for operator overloading, absolutely.=20 > Yet Go is essentially built around routines and concurrency which is = an incredibly complicated feature. I think that there is certainly = complexity in operator overloads, but I feel (and will attempt to = demonstrate with this RFC) that the benefits are worth the complexity. As someone whose two languages are PHP and Go I am not sure Go is = "essentially built around routines and concurrency." I find Go to be = much more than that. =20 However, that debate is a digression from our topic so we shouldn't = further it here. > Well, the first answer would be that I use PHP for my day job. I also = use Python, but much more sparingly. Python can accomplish all the = things that I want to do... I mean NumPy and SciPy exist and cover = virtually every math case that has even been hinted at so far in this = thread. But PHP is the language I enjoy the most. That at its core is = why I started writing a math library for PHP years ago. I like the = language, and I want it to be better, and I wanted to contribute = something to help people accomplish goals that were difficult to = accomplish in the language. That's still my motivation now, and that's = one of the things I hope to achieve with this RFC. Fair point. > R and Haskell are also very capable math languages, yet all three = languages are used. I don't think the idea that another language has = better tools for a particular task is an argument against making PHP = more capable at that task. True.=20 Unless adding those tools make it less capable at the tasks its best = for. And I am arguing that adding generic operator overloads for all = classes may well make PHP less capable for those who want to write = robust and reliable web applications. =20 (If we add value object classes and add generic operator overloads = there, I feel much less concerned about PHP becoming less capable of = achieving robustness and reliability.) > They are deterministic for given *values* and *types*. They are not = deterministic over the whole category. I think that may be a distinction without a difference. > However your suggestion is an excellent one. I will add some = interfaces and abstract classes to that repository when I am able to = illustrate what user implementations (or the PHP expressions of the C = implementations) might look like. AWESOME! > The overloaded operators don't interfere with anything *at all* unless = you use an object that has them defined, even if you use the extensions. = The GMP operator overloads don't affect anyone unless they are using = GMP. These will be the same, in that the operators are unaffected unless = a class opts in to using the feature. Yeah. I don't think I was saying those overloaded operators affect = anything else. I was suggesting that approach as a potential model. One final question. Let's assume that the functionality in your library = were to be added to PHP such that your library was no longer needed. = Would you be fine with that, or do would you prefer that features added = to PHP made your library more attractive as opposed to no longer needed? I'm not suggesting anything untoward =E2=80=94 it would be perfectly = reasonable IMO for you wanting features to enhance your library vs. = eliminate the need for it =E2=80=94 I am just interested to know which = avenue you would find most compelling? -Mike P.S. I've seen when language features are added that eliminate the need = for selected domain-specific libraries it can actually give the library = author room to provide even more specific functionality and increase the = library's value and thus increase the library's adoption, rather than = killing it. #fwiw