Any way to multiple dispatch on functions?`

I defined two abstract types, call them MyType and MyFrozenType{T<:MyType}.

Subtypes SpecificFrozenType <: MyFrozenStruct{SpecificType} are usually defined as SpecificFrozenType(x::SpecificType, v::Vector)

Now, I have a series of functions of the form f(y::SpecificFrozenType) for different inputs of subtypes of MyFrozenType. Is there a way to generically create functions of the form f(x::T, v::Vector) where T<: MyType = f(SpecificFrozenType(x, v)).

It’s tedious to rewrite this form for every concrete type, but I’m not sure what’s a more convenient way to do what I want to do.

Edit: I’m adding a MWE to clear up any confusion

abstract type MyType end
abstract type MyFrozenType{T<:MyType} end

struct Type1 <: MyType end
struct Type2 <: MyType end

struct Frozen1 <: MyFrozenType{Type1} 

struct Frozen2 <: MyFrozenType{Type2}

f(y::Frozen1) = y.v
f(y::Frozen2) = 2 * y.v

f(x::Type1, v::Vector) = f(Frozen1(v))
f(x::Type2, v::Vector) = f(Frozen2(v))

What I’m trying to do is not have to type the last two lines for all the types I’m defining.

You can generate the code in a loop like this for example:

for f in (:foo, :bar, :baz, ...)
    @eval $f(x::MyType, v::Vector) = $f(SpecificFrozenType(x, v))

So I should have been clear that SpecificFrozenType also changes from function to function. Its the sole concrete type of MyFrozenType{SpecificType} for each SpecificType.

Also wouldn’t @eval affect performance somehow? I’ve always avoided using it in my code. I’m not familiar with metaprogramming at all.

Perhaps this then?

for (f, t) in ((:foo, :SpecificFrozenTypeForFoo), (:bar, :SpecificFrozenTypeForBar), ...)
    @eval $f(x::MyType, v::Vector) = $f($t(x, v))

No, the example above is equivalent to

foo(x::MyType, v::Vector) = foo(SpecificFrozenTypeForFoo(x, v))
bar(x::MyType, v::Vector) = bar(SpecificFrozenTypeForBar(x, v))

Could you write up a MWE because it’s legitimately confusing which names are proper variables and which names are placeholders for multiple variables. Just write 2 types for the latter, your desired outcome won’t be too large to write out and it’d be clearer what we’re trying to shorten.

Apologies. I’ve edited my post with a MWE.

I think this is what I want!

So with @eval I’m allowed interpolate from symbols into objects with that name? I was always under the impression that eval() should be used as a last resort.

What does the @eval x do exactly? Is it the same as eval(x)?

Excellent example. So you have somewhat of a mapping from Frozen_ to Type_ which you can leverage with typeof(Frozen1instance.x) or fieldtype(Frozen1, :x), though it’s not good to rely on the field being named x. However, you really want a mapping from Type_ to Frozen_, which can be done in methods like those f one by one, which a @eval loop can help with.

My suggestion would be to decouple those methods from f since it looks intended for specific algorithms, so you’d have to do it all over again for say, g. Which I guess you can do with another nested @eval loop, but the less we put on that the better.

# must specify one by one
f(y::Frozen1) = y.v
f(y::Frozen2) = 2 * y.v

# 1 method links the type mapping to f
f(x::MyType, v::Vector) = f(freezemytype(typeof(x))(v))

# one by one, pattern can @eval loop
freezemytype(::Type{Type1}) = Frozen1
freezemytype(::Type{Type2}) = Frozen2

# must specify one by one
g(y::Frozen1) = y.v
g(y::Frozen2) = y.v / 2

# 1 method links the type mapping to g
# can @eval loop over f, g, etc
g(x::MyType, v::Vector) = g(freezemytype(typeof(x))(v))

More like eval(:x). Both do Core.eval(@__MODULE__, :x), where @__MODULE__ expands to the enclosing module. @eval is just convenient to save writing (:()) or (quote end) around a source code block. If you work with a direct Expr instance instead of source code, use the function instead of the macro.