I am struggling to find the right design due to the shear amount of possibilities, so I need help
Given a type FooID
, which is a simple number with a bit of additional convenience attributes (I added that to to show that I cannot do a simple type alias to Int32
):
struct FooID
value::Int32
q1::Int8
q2::Int8
q3::Int8
function FooID(value)
d = digits(abs(value), pad=3)
return new(value, d[1], d[2], d[3])
end
end
This type is now used as field type in
struct Bar
fooid::FooID
end
Now I need to define a ton of functions which take either FooID
, Bar
or even a simple Integer
. I tried different ways to provide a general API and this is the best solution I have found so far:
convert(::Type{FooID}, bar::Bar) = bar.fooid
convert(::Type{FooID}, x::Integer) = FooID(x)
function isvalid(x)
x = convert(FooID, x)
x.fooid.q1 == 1
end
function hasfuture(x)
x = convert(FooID, x)
x.fooid.q1 > 2
end
This works, but I have to repeat that convert
line everywhere. I also tried promote
, promote_rule
and Union
things, but I would like to keep the API clear and understandable and could not find a better way yet.
The first idea was to define
hasfuture(x::FooID)
and then implement prmote_rule
to do the automatic conversion when a user falls it with Bar
, but I don’t like that since it does not clearly communicate that it also accepts a Bar
.
Another approach is to define
hasfuture(x::Union{FooID, Bar, Integer})
but that also doesn’t feel right either.
I also thought about using a type hierarchy and introduce an AbstractFooID
where everything derives from, but of course Integer
will still be a special case…
Is there a more Julian approach to this?