Hi Tim, Barney,

> Your `Money` example would allow for unsound and/or non-sense behavior, such 
> as:
> 
> $fiveEuros = new Money(5, 'EUR');
> $tenDollars = new Money(10, 'EUR');
> 
> $what = $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

> I've already sent a sibling email, explaining why I believe that making the 
> Number class not final is a mistake. However I'd also like to comment on that 
> specific bit of your email:
> 
> I strongly believe in misuse-resistant APIs. Users should generally be 
> steered towards making 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 they 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* API, 
> not just an *okay* API should be part of the consideration. APIs within PHP 
> need to survive for 10+ years.

Thanks for that very important point, Tim. I was designing classes with GMP in 
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 just 
> 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 
> 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 be 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 any 
> differently to a class with no mutable properties. I prefer the behavior of 
> the latter.
> 
Due to the points Tim mentioned, I decided 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 values ​​not 
being set in the constructor.

Regards.

Saki

Reply via email to