News for hackers. Stuff that matters.
Re:Kotlin Money by yafetn on Tuesday October 08, 2024 @09:59AM (#41777466)
The currency codes could probably be inline value classes. That way, you can do

    val price = 100 money USD
Note the lack of quotes around USD.
Re:Kotlin Money by sigh_again on Tuesday October 08, 2024 @11:41AM (#41778580)
Maintaining an up to date currency list is, quite frankly, hell. Your code will always, always be more up to date than said list.
Re:Kotlin Money by 946789987649 on Tuesday October 08, 2024 @11:47AM (#41778664)
You could argue the same for timezones in a date library, yet they have them. I would think a library dedicated to money will in fact be the most up to date.
Re:Kotlin Money by sigh_again on Tuesday October 08, 2024 @11:51AM (#41778718)
Do they ? I've never once had a library that stores Europe_Paris, or Offset_Plus_7_45, they've always been stringly typed. Do you have an example of who'd be crazy enough to maintain a wrapper around tzdb?
Re:Kotlin Money by Tainnor on Wednesday October 09, 2024 @09:50AM (#41787972)
This could be mitigated by making the currency interface / abstract class open to extension by the user. The common currencies would be provided by the library and any additional ones could be defined by the user.
Re:Kotlin Money by sigh_again on Wednesday October 09, 2024 @04:01PM (#41792019)
Making currencies a concrete implementation is a terrible idea. There is no benefit to it at all, except throwing OOP into something that doesn't need it. A single Money class covers all needed cases, the difference between USD and BTC is... everything. Different smallest denominations, different formats, different everything. You don't even need concrete implementations

    private data class Money<T>(val name: String, val amount: Int) {
         operator fun <U : T> plus(other: Money<U>): Money<T> {
             return Money(name, amount + other.amount)
         }

         fun <U> plus(other: Money<U>, converter: (Money<U>) -> Money<T>): Money<T> {
              return converter(other) + this
         }
    }

    private object EUR
    private object USD

    val eur = Money<EUR>("EUR", 10)
    val usd = Money<USD>("USD", 20)

    usd + eur // error
This gives you entirely user defined currencies, does not pollute the global scope with unneeded currencies, allows you to plug in any conversion technique (pop off, make a network call), and fails if you try to add USD and EUR without converting one into the other.

Currencies should always be the user's responsibility to provide.

Re:Kotlin Money by Tainnor on Thursday October 10, 2024 @03:07PM (#41802277)
> except throwing OOP into something that doesn't need it

I feel like you're jumping to wild conclusions. All I'm suggesting is to change your code to

  private object EUR : Currency
  private object USD : Currency

  data class Money<C : Currency>(...) { ... }
That's just an empty tag interface and that's not particularly hardcore OOP, you can do the same thing with Haskell typeclasses.