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 > > >