I'm not sure how to create a simple Currency type

I want to extend Int (or UInt64 specifically, if needed) and do a couple things:

Override the comparison (<=>) operators to compare against the value divided by 1000.

Override the to_s method to format it appropriately.

But you can’t inherit from Int, since it’s a struct. How do you create a new reference type based on another reference type? I’m sure there’s a way, but I got lost. Do I need to box it, even though it’s actual data is still a reference type?

I think your best bet would be to use the decorator pattern and wrap an integer value to expose your API. Then if you wanted you could monkey patch in helper methods like 7.dollars, similar to how 4.hours works.

class Dollar
  include Comparable(self)

  def initialize(@value : UInt64); end

  # ...
end

The catch of course being it wouldn’t be compatible with your usual Int type restrictions, but I don’t think there’s a way around that.

1 Like

Id consider that a feature. Such value types are distinct types exactly for the reason that they are not just a dimensionless number value.

2 Likes

I appreciate the assistance. I’m attempting to move from Ruby to Crystal for my own personal coding, and learning the differences in best-practices is a challenge that their superficial similarity shrouds.

Also I would use a struct not a class for this:

struct Dollar
  include Comparable(self)

  def initialize(@value : Int64); end

  # ...
end

That way it’s a value type, GC is not bothered and you can still customize the to_s as wanted.
Doing this composition instead of inheritance of Int allows you to not treat values of Dollar as Int which I agree with @straight-shoota is an upside.

3 Likes