I have a struct representing the remainders of an integer with respect to several moduli. All of the moduli fit into Int64
except for 2^64
, so every modulus is either an Int64
or Type{Int64}
.
struct LooseGoose{N}
remainders::NTuple{N,Int64}
moduli::NTuple{N,Union{DataType,Int64}}
end
import Base: *
*(g::LooseGoose, r::Int64) = LooseGoose( mod.( widen.(g.remainders) .* r , g.moduli) .|> Int64 , g.moduli )
LooseGoose((4,7,12),(Int64,11,17)) * 7
This works fine, except in practice I always want the first modulus to be Int64
and the remaining moduli to be numeric. Is there a convenient way to specify this in the type definition without the Union
. I can enforce this in a constructor.
struct StrictGoose{N}
remainders::NTuple{N,Int64}
moduli::NTuple{N,Union{DataType,Int64}}
function StrictGoose(remainders::NTuple{N,Int64}, moduli) where {N}
moduli isa Tuple{DataType, (Int64 for i=2:N)...} || throw(ArguementError("moduli of incorrect form"))
new{N}(remainders,moduli)
end
end
StrictGoose((4,7,12),(Int64,11,17)) # Succeeds
StrictGoose((4,7,12),(13,Int64,17)) # Throws an error
- Is there a way to eliminate the
Union
and specifyTuple{DataType, (Int64 for i=2:N)...}
more directly in the type definition? - If the type of
moduli
is going to be restricted by the constructor anyway should I eliminate the annotation in the type declaration? - Would I be better off using
0
as a sentinel value forInt64
so myGoose
can beisbitstype
, but then having to replacemod
with something that watches for this value?
modif(a,b) = b==0 ? a : mod(a,b)