On 5 April 2024 19:30:24 BST, Jordan LeDoux <jordan.led...@gmail.com> wrote:
>A composed class
>does not somehow prevent the accidental error of mixing currencies, it just
>moves where that error would occur
It does not prevent someone accidentally *attempting* to mix currencies, but it
absolutely prevents that mistake leading to bogus values in the application,
because the methods available can all detect it and throw an Error.
If the class has a mixture of currency-aware methods, and methods / operator
overloads inherited from Number, you can end up getting nonsensical results
instead of an Error.
>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 = $val1->getCurrency();
>$val2Currency = $val2->getCurrency();
>$val1 = $val1->convertToCommonCurrency();
>$val2 = $val2->convertToCommonCurrency();
>// perform the necessary calculations using operators
>$answer = $answer->convertToCurrency($userCurrency);
>```
You have missed out the key section: how do you actually add the two numbers?
The addition MUST enforce the precondition that its operands are in the same
currency; any other behaviour is nonsensical. So the definition of that method
must be on the Money class, not inherited from Number.
If the add() method on Number is final, you'll need to define a new method
$val1->addCurrency($val2). The existing add() method and operator overload will
be inherited unchanged, but calling them won't just be useless, it will be
dangerous, because they can give nonsensical results.
That's what makes composition the better design in this case, because the Money
class can expose only the methods that actually have useful and safe behaviour.
The fact that the composed class can't add its own operator overloads is
unfortunate; but allowing inheritance wouldn't solve that, because the
inherited overloads are all wrong anyway.
Regards,
Rowan Tommins
[IMSoP]