Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:115671 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 23093 invoked from network); 9 Aug 2021 10:19:23 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 9 Aug 2021 10:19:23 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id E22A1180088 for ; Mon, 9 Aug 2021 03:49:35 -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-f169.google.com (mail-qt1-f169.google.com [209.85.160.169]) (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, 9 Aug 2021 03:49:35 -0700 (PDT) Received: by mail-qt1-f169.google.com with SMTP id d9so12047074qty.12 for ; Mon, 09 Aug 2021 03:49:35 -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=JZNIj/rVD9fQITif5zpZx1MM84Oijo7RyepAX7Wd/RQ=; b=gbn5+9sYj3BBioBQS70P/ruXyPetZELXUAa7PUm9S1NqD19RJzpahdSdXjuhor0W8t 8A6L98WMfOSrwv1HJ4gf+QpQ/Hdh2967AJ+Umm1m9XVxhykWOL+lI+qGgUaf1kA/VEbB cA9mxUWWMT1sbcS81UIqcGbqxk6UABzf4L/fnFXsEEG/Oj0Fuz0cF1itjOQiDqJsgtAs Sfke5cln3Kwr7IXpGTYUkvV1PXkGfl37LR78ZCQzBgfIncgW4/UeYlO/cYoMW4pg5sst 99FYOg+mmNGvYAcC0S1Qu+vX/AWksBpVQMQObrSwQaP+KNmQOaaw37OPXwKPCYvxc98F wmjw== 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=JZNIj/rVD9fQITif5zpZx1MM84Oijo7RyepAX7Wd/RQ=; b=pvqGNMkkTcLklkdawgH3Jn6cJGASbIyKnNhwVLMBy3365gbZBZJhpWnEaKlKj2Y10n Gwzfkh+v1SLQ3ttmKKUfzS7wwQb/5QCa55o7ezbPs+1ZPjuh+F1SxW20FVSU6rum6rL9 j5tDqMYj/z+qTMkNEgC5qjdniAe+FyTfEgjcwQM6kdh0YD4BLax7sFbNdd3jpfzeIPDk AyJhBFEzHJQp93ODWJrq5ht2O7m2NyYvJ8ZPwIgNcm8/BZEQJvGm14MVxkxxRyzGJxph scTUDE6jmAwhjqxhlpsEhZQXeCx0m1spBar98ZJ01h/vPht7tYjQSm+2tP46aM8ao6lz u1Jg== X-Gm-Message-State: AOAM531irhyLZEdyjJU1vn6d59P27h+Wx3iTPDRcmhD5kRb6/IGG0DuZ BLUxNg/m3XDNswIZyc+608yV8g== X-Google-Smtp-Source: ABdhPJxGfel7BkIFsGt+la+Zuwk13CTum11YdSufLvYsdOrlP3Y4HdsgpF8w3o+L1KZZJv/jVqkIHw== X-Received: by 2002:ac8:4e83:: with SMTP id 3mr2679202qtp.221.1628506173077; Mon, 09 Aug 2021 03:49:33 -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 w185sm9099873qkd.30.2021.08.09.03.49.31 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Mon, 09 Aug 2021 03:49:31 -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: Mon, 9 Aug 2021 06:49:30 -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 8, 2021, at 3:41 AM, Jordan LeDoux = wrote: >=20 > Off the top of my head here are some of the use cases that I think = benefit greatly from this: >=20 > - Complex number objects > - Fractions objects > - Matrix objects (math) > - Vector objects (math) > - Time/Date intervals > - Collections > - Arbitrary precision numbers (which are usually represented as a = string in PHP) Thank you for going to the effort to list those out. I'd like to = categorize them, if I may? ------------------------ General Purpose - Collections I'm not sure if you there is something about Collections related to Math = that makes them applicable for operator overloading but otherwise I = would be question whether there would be a strong consensus around what = operators a collection would implement and how those operators would = behave. =20 If you think there would be a strong consensus regarding collections and = operators maybe you could elaborate on which operators would apply and = what each would do? ------------------------ Date/Time - Time/Date intervals This seems to me to be a great use-case. Ironically we already have the = DateInterval class as well as methods that operate on DateTime objects = that add and subtract DateIntervals as well as proving the different = between two dates. Because we already have the classes, this seems to be a perfect place to = start with an RFC to introduce operators to PHP for DateTime and = DateInterval objects. =20 More on this in a bit. ------------------------ Math - Complex number objects - Fractions objects - Matrix objects (math) - Vector objects (math) - Arbitrary precision numbers (which are usually represented as a string = in PHP) And these all seem like strong candidates for classes that could use = operators. =20 But mathematical concepts are pretty well set in stone; are there really = this many different ways to implement them (rhetorical question)?: > Here are some actual user libraries which would probably use them: >=20 > - samsara/fermat (this library is mine as a matter of disclosure) > - brick/math > - markbaker/complex > - markbaker/matrix > - krowinski/bcmath-extended > - malenki/math > - markrogoyski/math-php > - rubix/tensor > - numphp/numphp > - mcordingley/linear-algebra Looking at the tests for just complex numbers in just three (3) of these = I see distinctly different choices, choices which appear to be = arbitrarily made by each developer: 1. = https://github.com/SamsaraLabs/FermatComplexNumbers/blob/master/tests/Sams= ara/Fermat/Values/ImmutableComplexNumberTest.php 2. = https://github.com/MarkBaker/PHPComplex/blob/3.0/unitTests/classes/src/Com= plexOperationTest.php 3. = https://github.com/malenkiki/math/blob/master/tests/Number/ComplexTest.php= I really can't critique the math aspects nor fully grok your use-cases, = but do I understand the benefit of standardization, and it seems like = PHP would gain greatly for use in the math domain by introducing classes = written in C and baked into core for each of your math use-cases. And the same with the Money classes that Rowan proposed. But I know you objected to that approach....more on that at the end. > As for constraints... well, if I had absolutely no concern for = implementation at all, and was just designing what constraints to put on = the magic methods, they would be: > 1. void is an unsupported return, and failing to return a value = results in an error. > 2. Variables outside the scope of the method cannot be set. This = includes properties on the object which is defining the magic method, = and includes sets that occur in called functions and methods. When I mentioned "constrained" I was referring to Rowan's distinction: > On Aug 7, 2021, at 3:07 PM, Rowan Tommins = wrote: > In a previous thread [1], I wrote about two fundamental design = approaches to operator overloading: >=20 > a) Treating operators as arbitrary symbols, which can be assigned any = operation which makes sense in a particular domain. > b) Treating operators as having a fixed meaning, and allowing custom = types to implement them with that meaning. Where a) would be "unconstrained" and b) would be "constrained." I = think you assumed I was referring to something else. > In any case, it is certainly possible that we could instead implement = some magic *objects* which can be extended that have built-in = overloading in specific ways. I think this is actually worse for the = following reasons: >=20 > 1. It would be far less obvious to the programmer that an object would = behave differently with a given operator, because the behavior wouldn't = be documented in the code itself. > 2. It would require many different implementations, some of them very = close to each other, to cover the same set of use cases. > 3. It would likely result in some maintainability concerns as more = users demanded different DSL type implementations be included in core, = and the existing ones would need to be maintained. I am going to challenge your justifications: ----- 1. When you speak of "not documented in the code" do you mean the = implementation would not be in PHP code? Okay, yet none of these = functions are documented in PHP code and they are all available in PHP: https://www.php.net/manual/en/ref.math.php AFAIK few people who do not struggle with programming or math have any = problem with these functions, because they are all documented. ----- 2. Yes, it would require many different implementations, one for each = use-case. Unique logic has to be implemented. Somebody has to do it. Why = is that a problem? I am not sure what you mean by being "very close to each other to cover = the same set of use-cases" unless you are talking about many different = arbitrarily different userland implementations, which I doubt since that = would be a reason not do add operator overloading. ----- 3. Regarding maintainability concerns. Code generally doesn't rot unless = the requirements change. Are requirements going to change? If yes, then = its not a strong use-case for operator overloading, in core or userland. = We should guard against operators used for convenience that are leaky = abstractions. BTW nobody can "demand" new features in PHP and be effective. But if = they propose them in an RFC it helps ensure these new features are fully = fleshed out, to the best of the list's collective ability. > As I've mentioned, while I understand that to many programmers = commutativity is a requirement of a good language, it is explicitly = incorrect to require commutativity for math operations. I only mentioned commutativity because others mentioned it. I personally = don't have the math chops so I defer to you here. > On Aug 8, 2021, at 7:25 AM, Jordan LeDoux = wrote: > On Sun, Aug 8, 2021 at 3:08 AM Deleu wrote: >> However my biased still exists: it would be awful to have to = understand >> what `+` is doing for every file of every library or even different = objects >> in the same project. >=20 > May I ask why? Python does not get much criticism that I can find for = its > implementation of operator overloading. > ... > There are many languages that provide operator overloading, and I've = never > seen it described as a bad feature in any of them. While it is hard to objectively quantify how much is "much" this = gentlemen =E2=80=94 a programming teacher =E2=80=94 had some choice = words to say about operator overloading specifically related to Python: https://medium.com/@rwxrob/operator-overloading-is-evil-8052a8ae6c3a A pull quote from his blog post:=20 "You wanna know what is not simple? Operator overloading. It has no = place in any language. It=E2=80=99s an aberration to be shunned." He feels even more strongly about the perils of userland operator = overloading than I do! > So while I'm aware of the concerns, I'm unconvinced they are founded = in > reality. That is, I think the concerns about maintainability and = complexity > may be unfounded in real world scenarios. However it is an extremely > consistent opinion here, and I would like to understand *why* it is = viewed > as bad for the language in a more concrete way if that is possible. Similarly I am unconvinced that adding operator overloading who not end = up making PHP programs brittle and that the community would come to = loath and wish we could turn back time to remove. Using operators for most classes would be a leaky abstraction. = Developers under the gun to deliver projects for their employers or = client are rarely going to take the in-depth time required to fully = understand the abstraction and all the ramifications of adding = operators, they are just going to do it because "it will seem like a = good idea at the time." And that will result in code using operators = where the concept of add, subtract, multiply, divide etc will be = constantly shifting as a project evolves. Just like what a method means = is constantly shifting. A while back someone proposed __ToArray and Rowan (among others) fought = back hard saying that the problem is that exporting an object to array = could mean different things to different people and there is often a = need to export to multiple different array format, and thus the use-case = should always be implemented as a named function. A first I was annoyed = that the list was pushing back because I wanted to use __ToArray, but = the more I thought about it the more I realized that Rowan and others = were right. Overloaded operators are no different than a __ToArray method. What does = __add() really mean for most classes? Most use-cases are not clear and compelling enough to elevate a named = function call to an operator. And for the relatively few use-cases that = *are* clear and compelling it would make sense for the use-case to be = fully fleshed out and then an object created in C and added to PHP, just = like DateTime and DateInterval were created. > If I wrote that in my RFC just to get the overrides that benefited the = work > I do, primarily around math, accepted into core, it would virtually > guarantee that actual operator overrides would never come for other = types > of applications. Every future RFC on this topic would be riddled with > comments about the existing abstract classes, and how all future > implementations have to be done in a similar way. This would = artificially > increase the barrier to acceptance for other domains in a way that I = do not > believe improves the language, serves the users of the language, or = allows > for flexible development of the language into the future. >=20 > So while I acknowledge that it may be a good middle ground (and even = one > that I personally would accept for my own implementations and code), I = am > unwilling to be the person that locks everyone *else* out of this = language > feature by making future RFCs more constrained and difficult to pass. >=20 > I constrained this RFC to math operators not because it's the only = domain > that would benefit, but because I think it's the one with the most > straightforward and understandable domain uses for everyone on this = list > and represents the "minimum" version of the feature. I appreciate that you have anxiety that if you don't get it all now, you = never will. I understand that, I feel the same way about the things I'd = like to see added to PHP. =20 But I have also realized that pushing through a feature too quickly can = have far reaching consequences and a damaging outcome. Better to take = small steps and allow time for the features to mature than to dive in = and make a mistake and have to live with it for the rest of PHP's useful = life. Given some people feel operator overloading is problematic in other = languages and some languages like Go explicitly chose not to add it it = would behoove us to tread very conservatively instead of just adding it = before we have any experience with operator overloading in PHP. Right = now we don't know what we don't yet know. If we were to =E2=80=94 for example =E2=80=94 start by adding operators = to DateTime and DateInterval it would give us real-world experience with = operators and objects before we fully commit to adding operator = overloading for all classes. We could then take our learning for DateTime and DateInterval and add = another class, maybe ComplexNumber.=20 Heck, we might even recognize value in creating an imaginary number = literal to support it; that type of domain-specific value won't happen = if we just focus on generic operator overloading.=20 Once we have ComplexNumber down, maybe we tackle a few more Math = classes, and many we even tackle Money. After a while, we'd have numerous classes in PHP supporting operators. = At that people we could have the confidence needed to decide it and how = to implement general-purpose operator overloading. But one thing is certain. While we can go from special one-off classes = that support operator overloading to later adding general-purpose = operator overloading, we cannot go the opposite direction. That makes = the idea of first testing out operator overloading on specific use-cases = a much less risky proposition that just adding general purpose operator = overloading from the start. -Mike=