If you don't need the flexible interrelations provided by J. Sarnoff's
approach, you might use metaprogramming like this:
abstract Cash
function _validate(p::Cash)
p.b >= 100 && throw(ArgumentError("Too much..."))
(p.b < 0 || p.a < 0) && throw(ArgumentError("Cannot have negative
amounts"))
end
macro make_currency(C)
esc(quote
type $C <: Cash
a::Int64
b::Int64
function $C(a::Int64,b::Int64)
this = new(a,b)
_validate(this)
this
end
end
# other boilerplate specific to C goes here
end)
end
for t = (:Usd,:Gbp,:Whole)
# show(macroexpand(:(@make_currency $t))) # for debugging
@eval @make_currency($t)
end
# specialize for the exceptional case:
function _validate(p::Whole)
p.a < 0 && throw(ArgumentError("Cannot have negative amounts"))
p.b != 0 && throw(ArgumentError("Must be whole amount"))
end
On Wednesday, August 24, 2016 at 1:35:19 PM UTC-4, Cliff wrote:
>
> As an example of what I mean, suppose that I'm trying to make a currency
> type for various currencies:
>
> abstract cash
>
> type usd <: cash
> a::Int64
> b::Int64
> function usd(a,b)
> b>=100 && error("Too much of smaller currency unit (over 99).")
> (b<0 || a<0) && error("Cannot have negative amounts.")
> new(a,b)
> end
> end
> type gbp <: cash
> a::Int64
> b::Int64
> function gbp(a,b)
> b>=100 && error("Too much of smaller currency unit (over 99).")
> (b<0 || a<0) && error("Cannot have negative amounts.")
> new(a,b)
> end
> end
>
> function Base.(:+){T<:cash}(x::T, y::T)
> total = 100x.a+100y.a+x.b+y.b
> return T(div(total, 100), total%100)
> end
>
> I'm able to define addition once for any subtype of cash. On the other
> hand, I have to write out a large amount of almost identical code each time
> I want to define a new subtype of cash. Is there some way I can define this
> once in an abstract manner (with any manually specified constructor
> overriding the general one), so that we could have something like:
>
> abstract cash
> general type T <: cash
> a::Int64
> b::Int64
> function T(a::Int64,b::Int64)
> b>=100 && error("Too much of smaller currency unit (over 99).")
> (b<0 || a<0) && error("Cannot have negative amounts.")
> new(a,b)
> end
> end
>
> type usd <: cash end
> type gbp <: cash end
> type whole <: cash
> function whole(a,b)
> a<0 && error("Cannot have negative amounts.")
> b != 0 && error("Must be whole amount.")
> new(a,b)
> end
> end
>
>
>