bojanz / currency

Currency handling for Go.
https://pkg.go.dev/github.com/bojanz/currency
MIT License
557 stars 45 forks source link

allow more uses of the zero value #16

Closed josharian closed 2 years ago

josharian commented 2 years ago

Hi! Thanks a bunch for this very useful package.

Consider summing a slice of amounts. The natural code to write is something like:

func Sum(amounts []currency.Amount) (currency.Amount, error) {
    var sum currency.Amount
    for _, x := range amounts {
        var err error
        sum, err = sum.Add(x)
        if err != nil {
            return currency.Amount{}, err
        }
    }
    return sum, nil
}

However, this code doesn't work, because sum gets initialized to the zero value, which has an empty currency code. Playground: https://go.dev/play/p/SzMyDcxcos7

I propose that Add and Sub the zero value (0 number, empty currency code) as special, and ignore currency mismatches in this case, adopting the non-empty currency code.

I also hit something similar in currency.Amount.Scan. I want to be able to store the zero value in the database, as a "not yet initialized, unknown currency" value. But loading such a value from the database using currency.Amount.Scan fails, because the empty currency code is not valid. I similarly propose that Scan have a special case for number = 0 and currency code consisting of all spaces ("" or " "), and allow it to be parsed without error.

Thanks again.

josharian commented 2 years ago

Oh, and I should say that I'm happy to send a PR, if this change is welcome.

It is a slight behavioral change, but one that turns an error into a non-error, so it shouldn't cause too many backwards compatibility problems.

bojanz commented 2 years ago

Thank you for your feedback, and for validating the approach in advance.

Both suggestions sound reasonable. I suggest doing them in separate PRs (one for Scan, one for the CurrencyMismatch on empty) to simplify merging.

bojanz commented 2 years ago

All done. Thank you, and welcome to the contributor list :)