Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:125579 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id CA71C1A00BD for ; Tue, 17 Sep 2024 09:14:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1726564599; bh=i5POvW0pxYWVtkIYpGGBhnkFtK2oiN6K4dTWzH1OmXM=; h=Subject:From:In-Reply-To:Date:Cc:References:To:From; b=dFVig6V5fxyGQ4gbiSefp+Ei34ww8JF3vZQmUyaFWVMbj5bKoCFd5Lj8jk7P4dpWx gWS73mVJobwAj/F0JoN3M8+M199SJGtz9t3YpI53ZvnFR7Wuku68K0SF3GRU9hPQt0 2tPC1vFeFkmS2hGbkTmeGRN3DOotT7ozcGUv/6fXGiVxo1/ra/tR0ftzQRiCy6XjX6 IiqnxLEyemxhO/8DKunmuU4BBYmAo3B3Ljm12rrPCGF6NbPhjTVQbA/6BgRs7CzMF2 1RipmNtfru1W4FMpDmObJQM4fI3i3xt/gbfGAYNZuN2WNqHFavD9DJk3EU0CS0bCx1 LSReYdSKEITkQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 6944318006A for ; Tue, 17 Sep 2024 09:16:38 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DMARC_MISSING,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H2, SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-yb1-f181.google.com (mail-yb1-f181.google.com [209.85.219.181]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Tue, 17 Sep 2024 09:16:38 +0000 (UTC) Received: by mail-yb1-f181.google.com with SMTP id 3f1490d57ef6-e1d0e1bffc8so4628601276.1 for ; Tue, 17 Sep 2024 02:14:33 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20230601.gappssmtp.com; s=20230601; t=1726564472; x=1727169272; darn=lists.php.net; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=C1xA3Y7sBFvk7igZcU6U5VnGY+41j9Y8XqtRl8rqC5E=; b=qeGIolU0bzSfrI9HKNl5vFAnZoWSOlBjoJXsNrBs8YBTqKZkgXtSotseUdyFWfpnEM /VLDhJIz/ia8PBm7AWjlpTR4P15WCSsEx4WHB9Cl5Lz8vzb5BkdYjKGdZaqnBcLwxsG5 OLj7RTmEUMckBL5oU6SoFQ31MxZX4HZW7FflX5KtlFT/C/C/BN5j0EC1JkTRvcH8SnhJ 6EZZhuusGt/jtu9A9Hl6+VGRNf9/k1K1VIe44SAPldvKJAzsPjxXqFJXwGRaeOMsr5ve 1hUMmI3ERxt4Sczbaf6MuyxU6trN33DgDkAv89zLSXBvQkgAiYsRchr+Ntm8sSzL5Gdo AqnA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1726564472; x=1727169272; h=to:references:message-id:content-transfer-encoding:cc:date :in-reply-to:from:subject:mime-version:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=C1xA3Y7sBFvk7igZcU6U5VnGY+41j9Y8XqtRl8rqC5E=; b=KPI883vjiNB0UyuV7Zp0zDz1kzihUchEkmbQxhiXebX94B+o7e7Zhh29vXw7UMKV6q N6sva0kb5heufP9ky1m/84ONSHAQnQ8NVKUBPcKbJI8ABAqFRGd4ZcoFgOOSVpOAvjl4 GOazlgYLOwWllcnIWpZGzO8OtB/IQCSyyxbkyEkwKjhocCpW7iL3TRm0pxv+O5yyBM6R IPjYn18tuLdUgKCVDQSFmq7OHDwFnTVGQoEU8/VR2QcDQMoKUqBvBFx5lhZ2WiDq8CbS rhttcIT+VTPdJSyozm2VOsO8Qb7iYa4WTQzcjtZZoP+t0fvYECPYPyTw4a/NQh5jZFvR ka5g== X-Gm-Message-State: AOJu0YxHi+O40JL4citQW6y8lEYUV5eD+j8l7CTRflyuDGuzLS9q0kxG VLSfOXXcl6NxQtrNbda4ab1Sz+6VHjiHeCHEzQuN0WD5WfAAMsl+nwyb1S9D34zZPI+uqkLXr0V s X-Google-Smtp-Source: AGHT+IGV35ADrwOVXaw0xPWA2cQfmGRO5xEVgsntZiQr0dOimBLOj2mc2RsO3zBUEELqGEPTcbKkuA== X-Received: by 2002:a05:690c:3806:b0:6db:e4bd:54ac with SMTP id 00721157ae682-6dbe4bd5904mr78818097b3.39.1726564472084; Tue, 17 Sep 2024 02:14:32 -0700 (PDT) Received: from smtpclient.apple (c-98-252-216-111.hsd1.ga.comcast.net. [98.252.216.111]) by smtp.gmail.com with ESMTPSA id 00721157ae682-6ddba585d50sm10899467b3.80.2024.09.17.02.14.31 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Tue, 17 Sep 2024 02:14:31 -0700 (PDT) Content-Type: text/plain; charset=utf-8 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow Mime-Version: 1.0 (Mac OS X Mail 16.0 \(3696.120.41.1.10\)) Subject: Re: [PHP-DEV] [Pre-RFC Discussion] User Defined Operator Overloads (again) In-Reply-To: Date: Tue, 17 Sep 2024 05:14:30 -0400 Cc: PHP internals Content-Transfer-Encoding: quoted-printable Message-ID: References: <18603813-9ECB-4486-95EE-08BEDECAB88D@newclarity.net> To: Jordan LeDoux X-Mailer: Apple Mail (2.3696.120.41.1.10) From: mike@newclarity.net (Mike Schinkel) > On Sep 17, 2024, at 1:37 AM, Jordan LeDoux = wrote: > On Mon, Sep 16, 2024 at 9:35=E2=80=AFPM Mike Schinkel = wrote: >=20 > Yes, if constraints of the nature I propose below are adopted. >=20 > The biggest problem I have with operator overloads is that =E2=80=94 = once added =E2=80=94 all code could potentially be "infected" with = operator overloads. However, if the developer *using* an operator = overload could instead opt-in to using them, in context, then I would = flip my opinion and I would begin to support them. =20 >=20 > What might opt-in look like? I propose two (2) mechanisms of which = each would be useful for different use-cases. As such I do not see these = two as competing but instead would expect adding both to be preferable: >=20 > 1. Add a pair of sigils to enclose any expression that would need to = support userland operator overloading. This would allow a developer to = isolate just the expression that needs to use operator overloading. I = propose {[...]} for this, but feel free to bikeshed sigils. Using an = example from the RFC, here is what code might look like: >=20 > $cnum1 =3D new ComplexNumber(1, 2); > $cnum2 =3D new ComplexNumber(3, 4); > $cnum3 =3D {[ $cnum1 * $cnum2 ]}; // Uses operator = operloading sigils > echo $cnum3->realPart.' + '.$cnum3->imaginaryPart.'i'; >=20 > 2. For when using `{[...]}` would be annoying because it would be = needed in so many places, PHP could also add support for an attribute. = e.g. `#[OperatorOverloads(Userland:true)]`. This attribute would apply = to functions, methods, classes, enums, (other?) and indicates that = operator overloads can be present anywhere in the body of the decorated = structure. I included `Userland:true` as an indicator to a reader that = this only applies to userland operator overloads and that built-in ones = like in GMP and anywhere else would not need to be opted into, but that = parameter could of course be dropped if others feel it is not needed. = Again, feel free to bikeshed attribute name and/or parameters. >=20 > #[OperatorOverloads(Userland:true)] > function SprintProductOfTwoComplex(ComplexNumber $cnum1, ComplexNumber = $cnum2)string { > $cnum3 =3D $cnum1 * $cnum2; > return sprintf("%d + %di", $cnum3->realPart, $cnum3->imaginaryPart); > } >=20 > If this approach were included in the RFC then it would also ensure = there is no possibility of BC breakage. BC breakage which would = certainly be an edge case but I can envision it would be possible,e = specially where newer instances incorporating operator overloads are = passed to functions that did not have parameters type hinted but were = not intend to be used with operator overloads resulting in subtle = potential breakage.=20 >=20 > This argument is also consistent with the argument people had about = not allowing default values to be generically used in calls to the = function function. Their claim was that developers who did not write = their code with the intention of exposing defaults should not have their = defaults exposed. Similarly developers that do not write their code to = enable operator overloads should not be used with userland operator = overloads unless they explicitly allow it, especially as they may not = have have tested code with operator overloads. >=20 > Anyway, that is my two cents worth.=20 >=20 > TL;DR? I argue that PHP should operator overloads but ONLY if there = is a mechanism that requires the user of expressions that call = overloaded operators to explicitly opt-in to their use. >=20 > -Mike >=20 >=20 > This is interesting, as I've never seen this in any language I = researched as part of operator overloading, and also was never given = this feedback or anything similar by anyone who provided feedback = before. If all language features required prior art, there would never be = innovation in programming languages. So for anything that currently = exists, there was always a first language that implemented it.=20 Of course when there is prior art we can use the heuristic of "All these = have done it before so it must be a good idea." But lack of prior art = should not be the reason to dismiss something, it should be evaluated on = its merits. > My initial reaction is that I do not understand how this is any better = than parameter typing. If you do not allow any objects into the scope = you are using operators, wouldn't that be the same as the kind of = userland control you are after? Or rather, how would it be substantially = worse? How would a developer know if they are using an object that has = operators, unless they study all the source code or at least the docs = (assuming there are good docs, which there probably are not?)=20 It might be illustrative to explicitly call out different scenarios I = envision in case some are not obvious. =20 There are: 1. Internal projects that are almost entirely bespoke code, with an = active team where the code is run by the code owners. Think a big = company's internal operations. 2. Agencies that build web projects using frameworks and libraries for = clients. 3. Smaller companies using frameworks and libraries for internal use, = with a small team that may have many other duties, or those who = outsource to contractors when they need things, and breakage for them is = can be very painful. 4. Framework developers 5. Library developers 6. And probably a bunch of other scenarios, each slightly different. Each of those scenarios have a different level of knowledge about the = code they work on. I'd expect #2 & #3 to have the least knowledge of the = code they use and would be most effected by other people's code doing = things they do not expect. I'd argue that #1 would have better knowledge of their code and would be = less affected by other people's code, except they probably have a huge = amount of bespoke code so one developer likely does not know what = another developer is doing, and especially if they have teams that = developer tools for other teams to use. Lastly #4 and #5 likely know their codebases the best, but they may = create footguns for developers in category #2 and #3 if the language = allows them to. And vice-versa. So back to your question "If you do not allow any objects into the scope = you are using operators wouldn't that be the same as the kind of = userland control you are after?" So I ask =E2=80=94 How do I know if the = objects I am using that were developed by others use operators or not? = With free-reign userland operator overloads we would be required to dig = into the source for the code written by others that we use to ensure I = know if they have operators and how they work.=20 OTOH with my suggestion, we will know because the code will crash when = no opt-in is used. Note, I refer to cases where code that calls code evolves, uses dynamic = programming, and/or accepts mixed types. And I am especially talking = about when developers create classes to wrap a built-in type and then = implement operators, but add special cases to them such as a String() = class that implements the concatenation operator but with a twist. > Your second example even includes a function that only accepts a = `ComplexNumber` object. I presume in your example there that if the = Attribute was removed, the function would just always produce a fatal = error, since that is the behavior of objects when used with `*`. Yes, that was the intention for the attribute, or lack of attribute in = the case you describe. >=20 > What it appears to me your proposal does is transform working operator = overloads into fatal errors if the user-code does not "opt-in". Correct. > But any such code would never actually survive long, wouldn't it? That is the feature, not a bug.=20 > Without the opt-in, these objects would ALWAYS produce fatal errors = (which is what happens now), Well, we do not have operator overloads right now. With operator = overloads they could run without crashing but have subtle bugs. =20 Note I am not referring to highly specific functions written for highly = specific classes which is what I suspect you are envisioning. Based on = your past comments those seem to be the areas you operate in, i.e. = math-related.=20 I am instead referring to code that is written to be generic but that = ends up running code it did not intend to run because of edge cases that = are exposed by userland operators. > which would eventually show up in testing, QA, etc. Eventually. Assuming they have a good testing and QA process which many = PHP projects do not. PHP is a least-common denominator language because = it is one of the easiest to get started with. Many less experienced PHP = developers do not have good testing and QA processes. But even if they do have good testing and QA, the sooner the bugs appear = the less likely they will get deployed. > The developer would realize that they (presumably) were trying to do a = math operation on something they thought was only a numeric type, and = then guard against objects being passed into that context with control = statements, parameter types, etc. Exactly. In my proposed concept they would rework their expressions to = opt-in to using the overloaded operators once they ensure that they = understand how the code operates. > So it seems to me what this ACTUALLY guards against is developers who = inadvertently don't type-check their variables in code where the = specific type is relevant. OR do not fully know the details of the types they are using. OR they are using types that have been upgraded to now support operator = overloading, but they do not realize that. > After one round of testing, all of the code using operators would = either always allow objects and thus overloads, or never allow objects = and thus not use overloads. That assumes they crash. I am concerned for when they do not crash but = instead have subtle bugs. > There shouldn't even be any existing code that would be affected, = since any existing code would need to currently allow objects in a = context where operators are used, which currently produces a fatal error = 100% of the time, (excepting internal classes which are mostly final = anyway, and thus unaffected by this proposal). It is correct that no old code can call other old code and use operators = on objects. But *new* code could call old code and then that old code could be made = to run operators without ever intending to be run in that manner. > What is the situation where your suggestion is implemented, a = developer does NOT opt-in to overloads, and they avoid unexpected = behavior without having to change their existing code to fix fatal = errors? I don't see how that is possible. In your hypothetical it appears you referred to only one developer. But = where I see issues is when there are two or more developers; a producer = of functions and a consumer of functions. Situation where there is free-reign userland operator overloading: = Junior developer Joe is using Symfony and learns about this great new = operator overload feature so decides to implement all the operators for = all his objects, and now he wants to start passing his objects to = Symphony code. Joe decides to be clever and implement "/" to concatenate = paths strings together but doesn't type his properties, and he ends up = passing them to a Symfony function that uses `/` for division, and his = program crashes with very cryptic error messages. He reports them to = the Symfony developers, and it wastes a bunch of time for everyone until = they finally figure out why it failed, because nobody every considered a = developer would do such a thing. Same scenario but with required opt-in. Joe does the same thing but this = time he gets a very clear message that says "Symfony Widget does not = support operator overloads." He googles and quickly finds out that what = that means and then goes to ask the Symfony team to support operator = overloads. They can choose to either add support, or not, but it is up = to them if they want to open the can of worms related to support that = operator overloading might cause. > Also, replying into a 3 year old reddit thread I linked to for = reference is not what I intended, however I want to highlight one other = thing you commented there but not here for some reason: >=20 > > To illustrate my point, imagine if we also allowed control structure = overloads. If we had them we could no longer read code and know that an = `if` is a branch and a `for` is a loop; either could be anything valid = for any control structure. Talk about ambiguity!=20 >=20 > Indeed. I want to make sure that I have not been ambiguous after = reading this, because I found it somewhat troubling: >=20 > I am looking at writing an RFC for specific *operators* that are = finite and defined within the RFC. I am not proposing something that = would allow control structures to be altered (I don't even think that = would be possible without essentially rewriting the entire Zend Engine = specifically to do it). >=20 > Operators are not control structures. Operators mutate the value or = state of a variable in a repeatable way, given the input states. There = is not even a generalized mechanism in my RFC for "arbitrary" overloads, = and the compiler was not implemented in a way that is generalized for it = either. It allows only exactly the operators that are part of the RFC, = and each are handled specifically and individually. I was ONLY using control structures as a more extreme analogy to = operator overloading to try to illustrate how =E2=80=94 the more things = you make configurable in a language =E2=80=94 the more you allow the = ground to shift beneath a developer's feet, so to speak. An approach I use when trying to understand something that might be = subtle is to ask myself what a more extreme example is that would be = analogous and then I consider that. =20 So I was not saying you proposed that, I was equating control structure = overloading to operator overloading, but I explicitly meant control = structure overloading would be a more extreme opening up of PHP than = operator overloading. =20 Clearly control structure overloading would be bad. I was trying to make = the point that operator overloading would cause problems for the same = reason, even if the problems would not be as extreme. I am sorry that my wording did not make it clear that I was using an = analogy, not referring to your RFC. Anyway, as a closing for this email, I know you badly want operator = overloading but there were enough people who disliked the idea to vote = against it last time so =E2=80=94 assuming my proposal could satisfy = them too =E2=80=94 it seems like a great compromise to give you true = operator overloading with just a little extra boilerplate while at the = same time allowing developers to limit the scope of operator overloads = to just those function where they want to enable it.=20 What's more, if after a few years we find out that my concerns really = were for naught then a future RFC could open it up and remove the opt-in = requirement.=20 But one thing is certain, if we open up operator overloading completely = one day one we could never go back to opt-in. -Mike=