money icon indicating copy to clipboard operation
money copied to clipboard

Should `Money.zero` have currency?

Open g-pavlik opened this issue 4 years ago • 6 comments

I'm on money-6.13.8

> Money.zero
=> #<Money fractional:0 currency:USD>
> Money.zero + Money.from_amount(1, 'gbp')
Money::Bank::UnknownRate: No conversion rate known for 'GBP' -> 'USD'
> Money.zero.currency
=> #<Money::Currency id: usd, priority: 1, symbol_first: true, thousands_separator: ,, html_entity: $, decimal_mark: ., name: United States Dollar, symbol: $, subunit_to_unit: 100, exponent: 2, iso_code: USD, iso_numeric: 840, subunit: Cent, smallest_denomination: 1>

but

> 0 + Money.from_amount(1, 'gbp')
=> #<Money fractional:100 currency:GBP>
> Money.from_amount(1, 'gbp') + 0
=> #<Money fractional:100 currency:GBP>

and also

> Money.zero == Money.from_amount(0, 'gbp')
=> true

I wanted to use Money.zero in my project instead of Integer(0) for consistency, but I can't (I can but only for comparisons, not as a starting point in Array#inject, etc). Just dropping it as an open question, I'm not sure what's the right answer given the possible implications to the rest of the project. Thank you :)

g-pavlik avatar Apr 14 '21 11:04 g-pavlik

Yes. All money objects should have a currency—even a nil currency—such that proper arithmetic is done at all times with them. That being said, .zero is just an alias for .empty and can have its currency set as seen here: https://github.com/RubyMoney/money/blob/main/lib/money/money/constructors.rb#L12

semmons99 avatar Apr 14 '21 11:04 semmons99

@semmons99 (sorry for long no reply, missed the notification).

I think I don't follow.

All money objects should have a currency—even a nil currency—such that proper arithmetic is done at all times with them

I'm not sure that I understood what you mean by nil currency.

> Money.default_currency = nil
> Money.zero
Money::Currency::UnknownCurrency: Unknown currency ''

I'd be fine with Money.zero having nil currency, then this could be doable Money.empty(nil) + Money.from_amount(100, "USD") == Money.from_amount(100, "USD")

In other words Money.zero behaving as Integer(0). But this is not what happens - I can't create Money with nil currency, and when I create it with whatever currency, I can't use it same way I'd use Integer(0)

What am I missing?

g-pavlik avatar Apr 21 '21 20:04 g-pavlik

Sorry, I mistyped my response. I meant to say

All money objects should have a currency—even a Money.zero object—such that proper arithmetic is done at all times with them.

In mathematics, we have to respect the units. You cannot add two numbers together with different units, hence even a zero needs a unit.

semmons99 avatar Apr 22 '21 15:04 semmons99

I don't think the problem is being understood here. It would be very useful if Money.zero was a special case that could be added or subtracted from another Money, regardless of whether the currency matches.

If I say Money.from_amount(1, 'gbp') + Money.from_amount(1, 'usd') ... then I rightly get an error saying I need to provide a conversion rate. Cool.

However, this ALSO gives me the error (unless the default currency is usd) Money.zero + Money.from_amount(1, 'usd') BUT, zero always converts to zero in any currency, so I should not need a conversion rate here.

The fact that I do need a conversion rate means that we have to write ugly code everywhere that checks if an amount is zero before we use it. Its quite annoying :)

for example: If I have two array of transactions, and I want to sum both arrays and then show the difference between those sums, I have to put in special case handling if one of the arrays is empty.

The other option is to use Integer(0) instead of Money.zero, but then I have to have ugly code whenever I format the result for display instead.

Edit: I note this was discussed way back when Money.zero was first implemented: https://github.com/RubyMoney/money/issues/195#issuecomment-7026417

perryn avatar Apr 20 '22 06:04 perryn

The special case code would need to be in the operator code and handle Money.zero being on the lhs or rhs. Anyone is welcome to develop a PR with this functionality for review and discussion.

semmons99 avatar Apr 20 '22 11:04 semmons99

Is anybody working this already? if not, I can work on this. Thanks.

deepakhb2 avatar Apr 26 '22 19:04 deepakhb2