Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122965 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 8B02C1A009C for ; Fri, 5 Apr 2024 12:10:46 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1712319075; bh=MXdsK520SkhfFHN8+Tng4GiqdhX/oQVWbdEwmcfbFkg=; h=Subject:From:In-Reply-To:Cc:Date:References:To:From; b=AvpjDhlk5+3tP9lSNSSvGC6r1o9gfxs96Es+cyZ8x3b5Op4xRYzBvz1emxw/CFzai r3/bBHoh0jkTWhxgS1Hrhfim3rjJ4LGbs5rLjOkynsLEebQ+GPmce8oaKgDlwo97+F BV6DN30yS+VvHlYsdzC2uPC/z/NGPEZMU1hVg1xESN0L6FpWO6vcQKg8Wgq197Mimn KlBp/QD9Yy35z0kdkje5nXJLr48G3uTnvWFinzdkJ4ww3jST4b8PfVvqHZb3W3cD61 sVWFFLa2G8tDjsuVqfOp6BVsGbaHzOOOjwFifC35KGwwqVPOiBxPZrqkuR/qYdmona D3vmufL35B24g== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 3494218007F for ; Fri, 5 Apr 2024 12:11:14 +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,HTML_MESSAGE, MIME_QP_LONG_LINE,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.sakiot.com (mail.sakiot.com [160.16.227.216]) (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 12:11:13 +0000 (UTC) Received: from smtpclient.apple (87.73.239.49.rev.vmobile.jp [49.239.73.87]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits)) (No client certificate requested) by mail.sakiot.com (Postfix) with ESMTPSA id 937D34005A; Fri, 5 Apr 2024 21:10:39 +0900 (JST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=sakiot.com; s=default; t=1712319039; bh=MXdsK520SkhfFHN8+Tng4GiqdhX/oQVWbdEwmcfbFkg=; h=Subject:From:In-Reply-To:Cc:Date:References:To:From; b=dS5qJQXEzSx6tLVT3KQnOYxgMPY66cueLfLxBN6DWX3U3bAm7gu7HMrG7T6Ghuzey H5P5cbYhYm6/EZY18sxKM8KmVQALQMmUBt9YLCc2JuzBO89EtrzUtBd/q2v5mGZSP7 WRv3diO/o3L5dMNSl735OTwYnuXcGQRGMmeavBqA= Content-Type: multipart/alternative; boundary=Apple-Mail-02C0E152-DAE3-4F91-A222-9A7EF45A93A2 Content-Transfer-Encoding: 7bit Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net Mime-Version: 1.0 (1.0) Subject: Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath In-Reply-To: <65bac481-628b-49c0-a87e-b54dd466fc0f@redmagic.org.uk> Cc: internals@lists.php.net Date: Fri, 5 Apr 2024 21:10:26 +0900 Message-ID: References: <65bac481-628b-49c0-a87e-b54dd466fc0f@redmagic.org.uk> To: Barney Laurance X-Mailer: iPhone Mail (21D61) From: saki@sakiot.com (Saki Takamachi) --Apple-Mail-02C0E152-DAE3-4F91-A222-9A7EF45A93A2 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Hi Tim, Barney, > Your `Money` example would allow for unsound and/or non-sense behavior, su= ch as: >=20 > $fiveEuros =3D new Money(5, 'EUR'); > $tenDollars =3D new Money(10, 'EUR'); >=20 > $what =3D $fiveEuros + $tenDollars; >=20 > What would you expect to be in $what? A `BcMath\Number(15)`? >=20 > ---------------- >=20 > The BcMath\Number class *should* absolutely be final, as a number is a num= ber is a number. Allowing extension just to be able to write $number->isPrim= e() instead of isPrime($number) will allow for very confusing code, such as t= he example above, with no way to work around it in userland. It also makes i= nteroperability between two different libraries that expect their own extens= ions to work very painful. >=20 > Consider the following example: >=20 > class PrimalityTestingNumber extends Number { > public function isPrime(): bool { } > } >=20 > class ParityTestingNumber extends Number { > public function isEven(): bool { } > public function isOdd(): bool { } > } >=20 > If I now want to create a function to check whether a number is an even pr= ime, I need to do something like this: >=20 > function isEvenPrime(Number $n) { > return (new PrimalityTestingNumber($n))->isPrime() && (new ParityTestingNu= mber($n))->isEven(); > } >=20 > 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 > I've already sent a sibling email, explaining why I believe that making th= e Number class not final is a mistake. However I'd also like to comment on t= hat specific bit of your email: >=20 > I strongly believe in misuse-resistant APIs. Users should generally be ste= ered towards making the right choice, even without needing to consult the do= cumentation. For example, by making the "right choice" the easiest choice or= by preventing "wrong choices" entirely. >=20 > Preventing folks from making wrong choices is overall less costly than the= m realizing that they made a wrong choice and then being unable to change it= , due to backwards compatibility or interoperability concerns. >=20 > PHP has enough gotchas as it is, so for any new API making it a *great* AP= I, not just an *okay* API should be part of the consideration. APIs within P= HP need to survive for 10+ years. Thanks for that very important point, Tim. I was designing classes with GMP i= n mind, so I overlooked the point you mentioned. For reference, classes that inherit from GMP return GMP. > Uninitialized is miles better than 0 I think. 0 is a meaningful number jus= t like any other and we should very strictly avoid inserting made up numbers= into people's applications. Let them fail fast, not output fake data. I'd r= ather my web shop crashes than gives things away for free. > Tim has convinced me that it should be a final class, in which case there'= s no meaningful distinction between a readonly class and a class with no mut= able properties. In that case just for simplicity I'd say it should be a rea= donly class. >=20 >=20 > If it's not a final class I think I'm not the right person to ask, since a= s I said I don't really like the fact that a readonly class behaves any diff= erently to a class with no mutable properties. I prefer the behavior of the l= atter. >=20 Due to the points Tim mentioned, I decided to make BCMath\Number a final cla= ss. And, as you say, for clarity's sake I would make it a read-only class. This also means that we don't have to worry about errors due to values =E2=80= =8B=E2=80=8Bnot being set in the constructor. Regards. Saki= --Apple-Mail-02C0E152-DAE3-4F91-A222-9A7EF45A93A2 Content-Type: text/html; charset=utf-8 Content-Transfer-Encoding: quoted-printable
Hi Tim, Barney,

Your `Money` example w= ould 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\Num= ber(15)`?

=
----------------

The BcMath\Number class *should* absolutely be final, a= s a number is a number is a number. Allowing extension just to be able to wr= ite $number->isPrime() instead of isPrime($number) will allow for very co= nfusing code, such as the example above, with no way to work around it in us= erland. It also makes interoperability between two different libraries that e= xpect their own extensions to work very painful.

Consider the following example:

c= lass 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 t= his "Extension Methods" proposal: https://externals.io/message/118395#118395=

I'v= e already sent a sibling email, explaining why I believe that making the Num= ber class not final is a mistake. However I'd also like to comment on that s= pecific bit of your email:
=
I strongly bel= ieve in misuse-resistant APIs. Users should generally be steered towards mak= ing the right choice, even without needing to consult the documentation. For= example, by making the "right choice" the easiest choice or by preventing "= wrong choices" entirely.

Preventing folks= from making wrong choices is overall less costly than them realizing that t= hey made a wrong choice and then being unable to change it, due to backwards= compatibility or interoperability concerns.

PHP has enough gotchas as it is, so for any new API making it a *great* A= PI, not just an *okay* API should be part of the consideration. APIs within P= HP need to survive for 10+ years.

Thanks for that very important point, Tim. I was designing classes with G= MP in mind, so I overlooked the point you mentioned.

=
For reference, classes that inherit from GMP return GMP.

Uninitial= ized is miles better than 0 I think. 0 is a meaningful number just like any o= ther and we should very strictly avoid inserting made up numbers into people= 's applications. Let them fail fast, not output fake data. I'd rather my web= shop crashes than gives things away for free.

Tim has convinced me that it should be a final class, in which case= there's no meaningful distinction between a readonly class and a class with= no mutable properties. In that case just for simplicity I'd say it should b= e a readonly class.

If it's not a final class I think I'm not the right person to ask,= since as I said I don't really like the fact that a readonly class behaves a= ny differently to a class with no mutable properties. I prefer the behavior o= f the latter.

Due to the points Tim mentioned, I deci= ded to make BCMath\Number a final class. And, as you say, for clarity's sake= I would make it a read-only class.

This also means that we don't have to worry about errors due to val= ues =E2=80=8B=E2=80=8Bnot being set in the constructor.

Regards.

Saki
= --Apple-Mail-02C0E152-DAE3-4F91-A222-9A7EF45A93A2--