Я ожидаю, что с диспетчеризацией типа вы, в конечном счете, по-прежнему будете вызывать после проверки на нечетное и четное, поэтому наиболее экономичный код, без пенического времени выполнения, будет заставлять вызывающую программу проверять аргумент и вызывать правильный функция.
Если вы, тем не менее, должны быть основаны на типах, по некоторым причинам, не связанным с эффективностью во время выполнения, вот пример такого:
abstract type HasParity end
struct Odd <: HasParity
i::Int64
Odd(i::Integer) = new(isodd(i) ? i : error("not odd"))
end
struct Even <: HasParity
i::Int64
Even(i::Integer) = new(iseven(i) ? i : error("not even"))
end
parity(i) = return iseven(i) ? Even(i) : Odd(i)
foo(i::Odd) = println("$i is odd.")
foo(i::Even) = println("$i is even.")
for n in 1:4
k::HasParity = parity(n)
foo(k)
end