Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122979 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 5F9781A009C for ; Fri, 5 Apr 2024 18:30:45 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1712341874; bh=ySh/kKzg7qAjLS9+tnQM04NfdoW+hhUaPFcwt95fRO8=; h=References:In-Reply-To:From:Date:Subject:To:Cc:From; b=EuH50tSki4BHRxvTnzAEpffrDQWj8ColzNvasM/zm954CwNkOe/aqrgvStqkF/ME0 AqfP6PwELUSdyzf5xLlPwSouBkD8/H8MgGdZwbQTr0J40UQ+gRCGV4jKXnJKa21gIG +epONBBescr1c7AtRB0mj2a9WAjnMBmD2QOOtByhrZAxFKf3i+z+KSTQes31AKgtMQ CIAjkdd7R1Z+QTnr4DichTb4KFtKWHz/4MxafX+E0JjfrH9dx4E8edzDA4/zYtYmZP BuGafrFILuemhbPKCMHhUwScLTWvNBtaswwzDofFkHFfYttvBwEn91hRhl583FofVz sLGQyYKKsFTWQ== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id CA48D180583 for ; Fri, 5 Apr 2024 18:31:13 +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.6 required=5.0 tests=BAYES_50,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS,FREEMAIL_FROM, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-pg1-f173.google.com (mail-pg1-f173.google.com [209.85.215.173]) (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 ; Fri, 5 Apr 2024 18:31:13 +0000 (UTC) Received: by mail-pg1-f173.google.com with SMTP id 41be03b00d2f7-5c66b093b86so2722720a12.0 for ; Fri, 05 Apr 2024 11:30:43 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1712341842; x=1712946642; darn=lists.php.net; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:from:to:cc:subject:date:message-id:reply-to; bh=lRbYP/GVNWqkeyKMjMAGkNH6eLwfA/MvC+PLZGPLNiU=; b=Moloa2UlivzCsi3D6UnH3RJKNTPYEFMs+Idl0EYFEA4+YeLtfKbFHp6p8OgVj2cjR4 vZJ4GOllv63mlO7C3oLwvGfAbR4M5W0g66RiO/xVx3DgQDNUTm2D22JkGKg89Df6UrdD qYggA60sV0LvcX8iBApFc89ElwvQNtUPBcu+DkURjywU51ksqZpaZdJAQ3y/TmbL6AwR hJRzRtHO/Lr1dmv+RsOArJY0m5n+6IcU4NFK0RTs1ILJX4EqJdsqyg852mNok66tGvpQ g3vQtVt16rFbhG3OEs92Ib3Ej6oPYUrgae36hBLRmiaGjiEycSKejk7EF9FpQclwVCKm EkbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1712341842; x=1712946642; h=cc:to:subject:message-id:date:from:in-reply-to:references :mime-version:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=lRbYP/GVNWqkeyKMjMAGkNH6eLwfA/MvC+PLZGPLNiU=; b=tboWFYAkV9Jm+DV9Mf7g2LnR0JqYLeXsPMJTnUJE22Tqq3WDlpCxIu3K4LEaNb4LG2 rDcp4d2jmnhIY4EAbD2+aPi8stxiYRW37Oim+3CHWkOdXvOR8UEGRKICY80bP72SZQTw xlwDCbubiOcOi63TWxQfR7lt7liqimDnEovOvhuI1k16NylA8vJA92x9syYwejDwaKXG othsdNifjo+gmOCIupXvJ3D60CmGu42jBXa6pYWf0JANjsQ0C98RUfpKMGcqe5GK/0xL oJRtLgQhia7ny3s35btz4DEGNYPGAKwEkMJF0hC8EEnuaqwKPSl0RykJTpQnMixJunUc HmJQ== X-Forwarded-Encrypted: i=1; AJvYcCX5eZLAXyiNgStfMciO5JRmUVdhSzSBURAY57C39vZ63uOLxFPq8OpGhgbrd40FObrCAdBxczLC1ymAdhMlV7xNtkJco3muTg== X-Gm-Message-State: AOJu0YwwYtnwWGwK5nxQ4EUYgzsPv5mktzT1J7nBa9QqvHghQeeHFwKx /QeJgSnjDfEgeP/c7PKTHHsW7u6VxPwC1hanfh1/zkKC2zAsxQFlkXkIbE2dlb8v4nuBtPCKYm4 930HxB5ghiIJJs9oJkivsdHRZUL8= X-Google-Smtp-Source: AGHT+IELTZY4zErjs6AWRa+Fm3PpLo3ChB7kZ/zYnshZvPCW4nSxLn7b6TpXsCXooqEqSZvyF6RlRDU1SbKpyElNCwk= X-Received: by 2002:a17:90a:f28b:b0:29b:fb23:863e with SMTP id fs11-20020a17090af28b00b0029bfb23863emr3240956pjb.17.1712341841901; Fri, 05 Apr 2024 11:30:41 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: <4F094EDA-5058-407D-AF39-06FD934FDE1F@sakiot.com> <68CF373E-6ABF-4471-8992-813B4BA1B508@sakiot.com> <904197f4-afb5-401e-9e17-7a655c5449d0@alec.pl> <655FEA80-9AB4-4AAD-A310-70ED968C97A2@sakiot.com> <8FB87901-02D7-4934-9119-55B21CEDDA9D@sakiot.com> <8035a2b2-f8dc-4a25-98eb-1d19c986bc75@bastelstu.be> In-Reply-To: <8035a2b2-f8dc-4a25-98eb-1d19c986bc75@bastelstu.be> Date: Fri, 5 Apr 2024 11:30:24 -0700 Message-ID: Subject: Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath To: =?UTF-8?Q?Tim_D=C3=BCsterhus?= Cc: Saki Takamachi , Lynn , Aleksander Machniak , php internals Content-Type: multipart/alternative; boundary="00000000000038831506155da75c" From: jordan.ledoux@gmail.com (Jordan LeDoux) --00000000000038831506155da75c Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable On Fri, Apr 5, 2024 at 2:48=E2=80=AFAM Tim D=C3=BCsterhus wrote: > Hi > > Your `Money` example would allow for unsound and/or non-sense behavior, > such as: > > $fiveEuros =3D new Money(5, 'EUR'); > $tenDollars =3D new Money(10, 'EUR'); > > $what =3D $fiveEuros + $tenDollars; > > What would you expect to be in $what? A `BcMath\Number(15)`? > > ---------------- > > The BcMath\Number class *should* absolutely be final, as a number is a > number is a number. Allowing extension just to be able to write > $number->isPrime() instead of isPrime($number) will allow for very > confusing code, such as the example above, with no way to work around it > in userland. It also makes interoperability between two different > libraries that expect their own extensions to work very painful. > > Consider the following example: > > class PrimalityTestingNumber extends Number { > public function isPrime(): bool { } > } > > class ParityTestingNumber extends Number { > public function isEven(): bool { } > public function isOdd(): bool { } > } > > If I now want to create a function to check whether a number is an even > prime, I need to do something like this: > > function isEvenPrime(Number $n) { > return (new PrimalityTestingNumber($n))->isPrime() && (new > ParityTestingNumber($n))->isEven(); > } > > This use case would be much better solved in a generic way using > something like this "Extension Methods" proposal: > https://externals.io/message/118395#118395 > > Well, since they are both in Euros, I would expect 15, but I expect that was a typo considering the variable name and it was meant to be 10 USD. As I said, you can accomplish the same through composition. For a money class, you'd likely need an extended method that checks the currency first, and then makes a call to the actual calculation method, which is essentially what the composing class would do as well, something like `addCurrency()`. Frankly, I don't think that making it final actually makes the API more resistant to errors, but it's also not something I care about enough to really fight for it on this RFC. I think it's the wrong choice, because the one example that I pulled up in this discussion does not constitute the entire breadth of use cases for this type of object, and I find myself extremely hesitant to suggest that we have thought of and considered all the various use cases that developers might have, or how they might be impacted by making the entire class final. Making it final will not reduce errors in my opinion, it will just make internals feel like those errors are less "our fault". A composed class does not somehow prevent the accidental error of mixing currencies, it just moves where that error would occur. Forcing composition drastically reduces the usability of the operator overloads, which I am opposed to, and I do not believe that this is being given the same kind of consideration. Once the class is forced to be composed, it can no longer be used as part of any kind of extensions either. I mentioned that I have a library that adds arbitrary precision functions for trigonometric functions (among others), to extend BCMath (and ext-decimal). A library that is solely focused on additional arbitrary precision math features should be the first in line to use this RFC, but I can tell you that if this class is final, I won't even update my library to use it at all, because there will be no point. The reason I did not mention MY use case is because I don't think many PHP developers are out there maintaining their own complicated trigonometric extensions to BCMath, so I don't think it's a good example of a common use case. Making it final also breaks with how other internally provided classes have been done in the past, many with no discernable issues. I do not see any mailing list discussions about the problems with DateTime being open for extension. If you want an actual answer about how a Money class would actually work in practice, it would likely be something like this: ``` // $val1 and $val2 are instances of the Money class with unknown currencies $val1Currency =3D $val1->getCurrency(); $val2Currency =3D $val2->getCurrency(); $val1 =3D $val1->convertToCommonCurrency(); $val2 =3D $val2->convertToCommonCurrency(); // perform the necessary calculations using operators $answer =3D $answer->convertToCurrency($userCurrency); ``` I would expect that most applications dealing with money are converting to a common calculation currency prior to actually doing any calculations, instead of relying on the conversion magically happening inside their calculation methods. So, your argument leaves me entirely unmoved. However, as I said, while this makes the RFC essentially useless to me, I don't think it's worth rejecting the RFC over, so I'll leave it at that. Jordan --00000000000038831506155da75c Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable


=
On Fri, Apr 5, 2024 at 2:48=E2=80=AFA= M Tim D=C3=BCsterhus <tim@bastelstu.= be> wrote:
https://externals.io/message/118395#118395


Well, since they are both in Euros, I = would expect 15, but I expect that was a typo considering the variable name= and it was meant to be 10 USD.

As I said, you can= accomplish the same through composition. For a money class, you'd like= ly need an extended method that checks the currency first, and then makes a= call to the actual calculation method, which is essentially what the compo= sing class would do as well, something like `addCurrency()`.

=
Frankly, I don't think that making it final actually makes t= he API more resistant to errors, but it's also not something I care abo= ut enough to really fight for it on this RFC. I think it's the wrong ch= oice, because the one example that I pulled up in this discussion does not = constitute the entire breadth of use cases for this type of object, and I f= ind myself extremely hesitant to suggest that we have thought of and consid= ered all the various use cases that developers might have, or how they migh= t be impacted by making the entire class final.

Ma= king it final will not reduce errors in my opinion, it will just make inter= nals feel like those errors are less "our fault". A composed clas= s does not somehow prevent the accidental error of mixing currencies, it ju= st moves where that error would occur. Forcing composition drastically redu= ces the usability of the operator overloads, which I am opposed to, and I d= o not believe that this is being given the same kind of consideration. Once= the class is forced to be composed, it can no longer be used as part of an= y kind of extensions either.

I mentioned that I ha= ve a library that adds arbitrary precision functions for trigonometric func= tions (among others), to extend BCMath (and ext-decimal). A library that is= solely focused on additional arbitrary precision math features should be t= he first in line to use this RFC, but I can tell you that if this class is = final, I won't even update my library to use it at all, because there w= ill be no point. The reason I did not mention MY use case is because I don&= #39;t think many PHP developers are out there maintaining their own complic= ated trigonometric extensions to BCMath, so I don't think it's a go= od example of a common use case.

Making it fi= nal also breaks with how other internally provided classes have been done i= n the past, many with no discernable issues. I do not see any mailing list = discussions about the problems with DateTime being open for extension.

If you want an actual answer about how a Money class w= ould actually work in practice, it would likely be something like this:

```
// $val1 and $val2 are instances of the= Money class with unknown currencies
$val1Currency =3D $val1->= getCurrency();
$val2Currency =3D $val2->getCurrency();
$val1 =3D $val1->convertToCommonCurrency();
$val2 =3D $val2= ->convertToCommonCurrency();
// perform the necessary calculat= ions using operators
$answer =3D $answer->convertToCurrency($u= serCurrency);
```

I would expect that mo= st applications dealing with money are converting to a common calculation c= urrency prior to actually doing any calculations, instead of relying on the= conversion magically happening inside their calculation methods.

So, your argument leaves me entirely unmoved. However, as I= said, while this makes the RFC essentially useless to me, I don't thin= k it's worth rejecting the RFC over, so I'll leave it at that.

Jordan
--00000000000038831506155da75c--