Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122945 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 D6F391ADA7B for ; Thu, 4 Apr 2024 21:13:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1712265251; bh=QI/B7xfa+djF2HK5I1f0rcVlIaXKD9qvTi2hhbDkTRw=; h=Date:Subject:To:References:From:In-Reply-To:From; b=XGZhZE+jqlTXhNdhELaWJjn9+QxAbV0xars+g4G20oxFe++X9J4UPc/EBQMggf3Gw Zbhjc21HtuK/PY0Mb9Bcmn2oWBalJuUgsu95FJnubgh7AqEPACfvBM6XrJsTYzkxlB iAx376w0vURnp7fUQxTXgdHKq8rThpIlidpD9yiyTes6L+GojS2bAYTL9OiXdE1cAb bfpGeNZx64rzat7zQS8hXYzN8ZwsuSRQD4E38rfRWJYauSFeHXb4ntixWiVB5cf78Y TO4RwOqQ6oM4bTO/5+U80q6eR4+z9hfN9sLFUs+4TafeDKuVKDzLItlXkWAF5csHoe PS2L3oO42BJkA== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 0D25B18007E for ; Thu, 4 Apr 2024 21:14:09 +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=1.0 required=5.0 tests=BAYES_50,DMARC_MISSING, HEADER_FROM_DIFFERENT_DOMAINS,HTML_MESSAGE,SPF_HELO_PASS,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 gliadin.co.uk (gliadin.co.uk [80.82.115.221]) by php-smtp4.php.net (Postfix) with ESMTP for ; Thu, 4 Apr 2024 21:14:06 +0000 (UTC) Received: from [192.168.0.17] (hari-18-b2-v4wan-169870-cust740.vm1.cable.virginm.net [92.239.242.229]) by gliadin.co.uk (Postfix) with ESMTPSA id A6065FA2698 for ; Fri, 5 Apr 2024 00:13:36 +0300 (MSK) Content-Type: multipart/alternative; boundary="------------XWH0YtFnTDRUR0xrVUNI6FYK" Message-ID: <65e0fc8b-ed4e-4bf8-af2d-77dc7b4bb934@redmagic.org.uk> Date: Thu, 4 Apr 2024 22:13:36 +0100 Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PHP-DEV] [RFC] [Discussion] Support object type in BCMath To: internals@lists.php.net 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> Content-Language: en-US In-Reply-To: From: barney@redmagic.org.uk (Barney Laurance) This is a multi-part message in MIME format. --------------XWH0YtFnTDRUR0xrVUNI6FYK Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit On 04/04/2024 01:54, Jordan LeDoux wrote: > > > On Tue, Apr 2, 2024 at 5:43 PM Saki Takamachi wrote: > > > If make a class final, users will not be able to add arbitrary > methods, so I think making each method final. Although it is > possible to completely separate behavior between method and opcode > calculations, this is inconsistent and confusing to users and > should be avoided. > > > Right, if a class is not final but has only final methods > (including constructor) and no protected properties then it allows > people to extend it but not break any encapsulation or (I think) > impose any more BC requirements on the maintainer (unless we care > about conflicting with method names of child classes when > updating). It lets people just do something a bit like adding > 'extension methods' in C#. I like it. People could write e.g. > `$bcChildNumber->isPrime()` instead of > `BcNumberUtils::isPrime($bcNumber)` > > > Yeah, I suspect the most common child class will be something like > "Money" that additionally has a parameter denoting what currency the > value is in, since that is by far the most common use case for > arbitrary precision math in PHP. Making the calculation methods final > should do fine in my opinion. I don't think it will be possible to make a good Money class as a child of this. BcNum is a read-only class, so if the constructor of BcNum is final then the child class won't be able to take the currency as a constructor param, and won't be able to protect the invariant that currency must be initialized. If the constructor of BcNum were made non-final then BcNum wouldn't be able to protect the invariant of the numeric value always being initialized once the constructor has returned. And it should be straightforward to make a good money class as a composition of BcNum and a currency enum or string. There's probably not any good use case for a subclass to add properties, unless perhaps the subclass developers are willing do do away with some of the checks that would normally be done on a value object by the PHP runtime to keep it valid (maybe replacing them with static analysis checks). But there are lots of reasonable use cases for subclasses to add methods, even if they're effectively syntax sugar for static methods with a BcNum typed param. Having just written that I've now checked the behavior of DateTime - see https://3v4l.org/5DQZg . The constructor of that isn't final, so a child class can replace it with an empty constructor. But if it does that and leaves the value uninitialized then it blows up on a call to `format`. That's probably not something we should emulate. DateTimeImmutable behaves the same way. --------------XWH0YtFnTDRUR0xrVUNI6FYK Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: 8bit
On 04/04/2024 01:54, Jordan LeDoux wrote:


On Tue, Apr 2, 2024 at 5:43 PM Saki Takamachi <saki@sakiot.com> wrote:

If make a class final, users will not be able to add arbitrary methods, so I think making each method final. Although it is possible to completely separate behavior between method and opcode calculations, this is inconsistent and confusing to users and should be avoided.
 

Right, if a class is not final but has only final methods (including constructor) and no protected properties then it allows people to extend it but not break any encapsulation or (I think) impose any more BC requirements on the maintainer (unless we care about conflicting with method names of child classes when updating). It lets people just do something a bit like adding 'extension methods' in C#. I like it. People could write e.g. `$bcChildNumber->isPrime()` instead of `BcNumberUtils::isPrime($bcNumber)`

Yeah, I suspect the most common child class will be something like "Money" that additionally has a parameter denoting what currency the value is in, since that is by far the most common use case for arbitrary precision math in PHP. Making the calculation methods final should do fine in my opinion.

I don't think it will be possible to make a good Money class as a child of this. BcNum is a read-only class, so if the constructor of BcNum is final then the child class won't be able to take the currency as a constructor param, and won't be able to protect the invariant that currency must be initialized. If the constructor of BcNum were made non-final then BcNum wouldn't be able to protect the invariant of the numeric value always being initialized once the constructor has returned. And it should be straightforward to make a good money class as a composition of BcNum and a currency enum or string.

There's probably not any good use case for a subclass to add properties, unless perhaps the subclass developers are willing do do away with some of the checks that would normally be done on a value object by the PHP runtime to keep it valid (maybe replacing them with static analysis checks). But there are lots of reasonable use cases for subclasses to add methods, even if they're effectively syntax sugar for static methods with a BcNum typed param.

Having just written that I've now checked the behavior of DateTime - see https://3v4l.org/5DQZg . The constructor of that isn't final, so a child class can replace it with an empty constructor. But if it does that and leaves the value uninitialized then it blows up on a call to `format`. That's probably not something we should emulate. DateTimeImmutable behaves the same way.


--------------XWH0YtFnTDRUR0xrVUNI6FYK--