# Dispatch on a set of value type parameters

I have a type which has an `Int` value parameter, let’s represent the type like this:

``````struct T{m}
some_fields
end
``````

I want to define a method for a function `f` that takes a `T` value, but only if `m` is part of a certain finite set, for example if `m` is either `2`, `3` or `4`. However I also need access to `m` within the function.

This is the cleanest solution I could think of, however I wonder whether it’s possible to have `m` as a type parameter within the `f` method:

``````m_val(::Type{T{m}}) where {m} = m

f(v::V) where {V <: Union{T{2}, T{3}, T{4}}} = 7*m_val(V)
``````

Another possible solution would be to have a separate method for each value of `m`, which seems like it would be horrible due to code duplication.

You may be able to play around with Value types but I think just adding `m` as a field simplifies things. You can keep the Int Type if you want for other methods. For example:

``````struct newType{M}
m::Int
A::Array{Int,M} #just some random field that depends on m (M==m)

function newType(M)
A = zeros(Int, ntuple(x->3,M)) #each axis has length 3
new{M}(M,A)
end
end
``````

Now you can create a function that takes in any version of the type and use `m`:

``````f(v::newType, finiteSet) = v.m ∈ finiteSet ? 7v.m : error("m not in set")
``````

If we make some instances of `newType` we can test `f`:

``````julia> v3 = newType(3);

julia> v8 = newType(8);

julia> typeof(v3)
newType{3}

julia> typeof(v8)
newType{8}

julia> finiteSet = [2,3,4];

julia> f(v3,finiteSet)
21

julia> f(v8,finiteSet)
ERROR: m not in set
``````

I’m not an expert on types so this might be bad advice but it avoids code duplication and works for any `m`.

Maybe I should have said this explicitly when asking the question, but the point of using compile-time dispatch is performance. Your solution wouldn’t have cut it because `f` was supposed to be called within hot loops.

The solution would be to use `StaticNumbers` and include `m` as a field in `struct T` something like this:

``````struct T{m}
some_fields
mm::StaticInteger{m}
end
``````

Note:

``````julia> Base.issingletontype(StaticInteger{3})
true
``````
1 Like

It seems like you’re already in good shape, and you’re just looking for ways to avoid polluting the global namespace with a new function that’s specific to `f`.

You can achieve this by declaring a local function:

``````julia> struct T{m} end

julia> f(v::V) where {V<:Union{T{2},T{3},T{4}}} =
let mval(::Type{T{m}}) where {m} = m
7*mval(V)
end

julia> f(T{2}())
14
``````

Another approach would be to access the property directly:

``````julia> f(v::V) where {V<:Union{T{2},T{3},T{4}}} = 7*V.parameters[1]
f (generic function with 1 method)

julia> f(T{2}())
14
``````

but this isn’t Julian. I don’t know of any method for accessing a type’s parameters; it’d be nice if we had `parametersof(::Type{T}) where T = Tuple(T.parameters)` but we don’t.

Hm this library is pretty cool. This looks like a good solution too.

1 Like

Also, if you want a more programmatic solution, you can use the `@generated` macro to produce different function body expressions depending on the argument types:

``````julia> @generated f(v::T{m}) where m = let
if m ∈ (2, 3, 4)  quote 7*\$m end
else  quote throw(string(\$m)*" not supported") end
end
end
f (generic function with 1 method)

julia> f(T{1}())
ERROR: "1 not supported"

julia> f(T{2}())
14
``````
1 Like

Ah makes sense. I’ll also have to look at `StaticNumbers` as well. I’m curious what the application is for this setup?

My goal (since abandoned because of various reasons) was to write an iterator that is a Cartesian power of another, wrapped, iterator. So basically a special case of the Cartesian product iterator from `Base.Iterators`.

``````struct T{m}
some_fields
end
``````

``````struct PowerIterator{m, It <: Any}
and I asked the question while trying to write specialized implementations for `Base.iterate` for a few small `m`, where `m` is the exponent in the Cartesian power.