# How to dispatch on a type alias?

**URL:** <https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476>\
**Category:** New to Julia\
**Created:** [November 20, 2023, 5:27pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476 "2023-11-20T17:27:46Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 20, 2023, 10:21pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/21 "2023-11-20T22:21:40Z")

</div>

You did not misunderstood, this kind of method definition is the right thing to do indeed. What you may have misunderstood is that i wanted to define all of them at once, and not them one by one:

> For any XXX defined as follows:
> 
> `const XXX{d,T} <: Archimedean{d,XXXGenerator{T}}`,
> 
> i want the method `generator(::type{MyTypeAlias}) = MytypeAliasGenerator` to exists.

and that is not possible wihtout metaprogramming.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 20, 2023, 10:23pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/22 "2023-11-20T22:23:33Z")

</div>

I actually did misunderstand, it slipped my mind that those are aliases. `generatorof(::Archimedian{d, Gen} where d) where {Gen} = Gen` extracts a parameter from an instance. Don’t need metaprogramming for that. However, you do need the parameter to have a value for the extracted parameter, which your aliases do. Actually let me fire up the REPL again for a better example.

EDIT: okay this one works on your aliases. Note that it works specifically on the 1-parameter types being aliased, not concrete subtypes or the supertype `Archimedean`.

```julia
julia> const Clayton{d} = Archimedean{d, ClaytonGenerator}
Clayton (alias for Archimedean{d, ClaytonGenerator} where d)

julia> generatorof(::Type{Archimedean{d, Gen} where d}) where Gen = Gen
generatorof (generic function with 1 method)

julia> generatorof(Clayton)
ClaytonGenerator

julia> generatorof(Archimedean{1, ClaytonGenerator}) # fails if concrete
ERROR: MethodError: no method matching generatorof(::Type{Clayton{1}})
...

```

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 20, 2023, 10:36pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/23 "2023-11-20T22:36:45Z")

</div>

Hum… I tried to translate your code to my starting example and it fails :

```julia
struct A{T1,T2}
    x::T1
    y::T2
end
struct B{T3}
    z::T3
end
# an alias : 
const C{T1,T3} = A{T1,B{T3}}
# and a constructor : 
C(x,z) = A(x,B(z))

generatorof(::Type{A{T1, Gen} where T1}) where Gen = Gen
# generatorof(::A{T1,Gen} where T1) where {Gen} = Gen

generatorof(C) 

```

Do this require `Gen` to be a singleton ? On your side, can you make hte same thing for `const Clayton{d,T} = Archimedean{d,ClaytonGenerator{T}}` ?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 20, 2023, 10:39pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/24 "2023-11-20T22:39:31Z")

</div>

It’s more apparent in the REPL printout, but `C` has 2 parameters:

```julia
julia> const C{T1,T3} = A{T1,B{T3}}
C (alias for A{T1, B{T3}} where {T1, T3})

```

The way `generatorof` is set up, it takes only parametric types varying on 1 parameter. Remember what I said earlier, method parameters must have specific values. It worked for `Clayton` because `Gen = ClaytonGenerator`.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 20, 2023, 10:42pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/25 "2023-11-20T22:42:25Z")

</div>

> [@Benny](#):
>
> The way `generatorof` is set up, it takes only parametric types varying on 1 parameter

Yes indeed. Is it posible to add variance on the second one too ?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 20, 2023, 10:46pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/26 "2023-11-20T22:46:23Z")

</div>

Yes, but it will depend on what you want to extract, a particular concrete type like `ClaytonGenerator{1}` or the parametric `ClaytonGenerator{T} where T`. In the first case, you’d pass in `Clayton{d, 1}`, in the second you’d just pass in `Clayton`. Could just keep 2 methods around for both purposes. Probably better to figure out the structure of your input and output types first before implementing the method.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 20, 2023, 10:47pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/27 "2023-11-20T22:47:21Z")

</div>

I want to pass `Clayton` and extract `ClaytonGenerator` 🙂

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 20, 2023, 10:50pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/28 "2023-11-20T22:50:29Z")

</div>

Right, but it’ll depend on how you’re setting up the `Clayton` alias, it’s not clear anymore how many unspecified parameters it should have.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 20, 2023, 10:51pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/29 "2023-11-20T22:51:12Z")

</div>

Ok so let’s specify it again give me a sec.

Edit: here is an up to date spec:

```julia
abstract type Generator end
struct Archimedean{d,T}
    G::T
end
struct ClaytonGenerator{T} <: Generator
    θ::T
end
const Clayton{d,T} = Archimedean{d, ClaytonGenerator{T}}

#generatorof(Clayton) -> Claytongenerator

# But also if i a user defines
struct GumbelGenerator{T} <: Generator
    θ::T
end
const Gumbel{d,T} = Archimedean{d, GumbelGenerator{T}}

# generator(Gumbel) should return GumbelGenerator

```

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 20, 2023, 11:29pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/30 "2023-11-20T23:29:25Z")

</div>

I see why it’s tricky, the earlier advice to use the REPL printout would mislead:

```julia
julia> const Gumbel{d,T} = Archimedean{d, GumbelGenerator{T}}
Gumbel (alias for Archimedean{d, GumbelGenerator{T}} where {d, T})

julia> generatorof(::Type{Archimedean{d, Gen{T}} where {d, T}}) where Gen = Gen
ERROR: TypeError: in Type{...} expression, expected UnionAll, got a value of type TypeVar
...

```

Type aliasing doesn’t introduce a 3rd parameter like that. In a shorter example:

```julia
julia> struct X{T, S} end

julia> Y{T} = X{T, Ref{T}}
Y (alias for X{T, Ref{T}} where T)

julia> X{T, Blah{T}} where {T, Blah}
ERROR: TypeError: in Type{...} expression, expected UnionAll, got a value of type TypeVar
...

```

The type system only sees `X{T, Ref{T}}` as a subtype of `X{T, S}`, not any type with a 3rd parameter; `Y`’s aliasing does not create any types. It’s not any different from `Z{T} = Ref{T}` not creating a supertype `Blah{T}`, ad-hoc supertyping is just too chaotic.

You can make a method `getBlah(::Type{Y}) = Ref`, and you could use the aforementioned metaprogramming to make more boilerplate methods for the others.

Only a full type can have a 3rd parameter, but I don’t think this is worth doing:

```julia
julia> struct X3{T, Blah, S} # cannot do Blah{T} with unknown Blah
         # constructor lacks S, but S remains as parameter
                                      # Blah is known here
         X3{T, Blah}() where {T, Blah} = new{T, Blah, Blah{T}}()
       end

julia> X3{Int, Ref}()
X3{Int64, Ref, Ref{Int64}}()

julia> X3{Int, Ref} # REPL now prints shorthand annoyingly
X3{Int64, Ref}

julia> X3 # ditto
X3

julia> X3{Int, Ref}.body # prints S
X3{Int64, Ref, S}

julia> X3.body.body.body # I forgot what internal method does this
X3{T, Blah, S}

```

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 21, 2023, 4:10pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/31 "2023-11-21T16:10:46Z")

</div>

@mbauman @Benny just to tell you that I ended up using the dumb approach, as i could not find a better way without resorting to meta-programming, which i do not like. The _true problem_ and its end result are there : [https://github.com/lrnv/Copulas.jl/blob/0b5822810077a50bf062be892be1d8051f03c484/src/ArchimedeanCopula.jl#L216-L254](https://github.com/lrnv/Copulas.jl/blob/0b5822810077a50bf062be892be1d8051f03c484/src/ArchimedeanCopula.jl#L216-L254)

Not pretty, but working 😂 Thanks to both of you anyway

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 21, 2023, 5:05pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/32 "2023-11-21T17:05:03Z")

</div>

“dumb” is subjective, but this `@eval` looping over Symbols does exist in Base Julia to implement many operators. You are right that it’s worth refactoring to a simpler system with a fewer types and methods when possible, but sometimes you really do need many very similar versions.

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 21, 2023, 5:47pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/33 "2023-11-21T17:47:32Z")

</div>

Based on Benny’s instruction (I mean the part of which I sort of understood):

```julia
julia> generatorof(::Type{S}) where {S <: Archimedean} =
  S.body.body.parameters[2].name.wrapper
generatorof (generic function with 1 method)

julia> generatorof(Clayton)
ClaytonGenerator

julia> generatorof(Gumbel)
GumbelGenerator

```

seems to get the job done (not so pretty for sure).

Or even less pretty:

```julia
function generatorof(::Type{S}) where {S <: Archimedean}
    S2 = hasproperty(S,:body) ? S.body : S
    S3 = hasproperty(S2, :body) ? S2.body : S2
    S3.parameters[2].name.wrapper
end

```

which covers the different cases (i.e. not just the alias but also concrete types).

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 21, 2023, 6:58pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/34 "2023-11-21T18:58:21Z")

</div>

@Dan I dont know how you did that, but thanks a lot. I will commit this, link this thread, and never think about it again, dear wizzards 😛

So I am trying to use it and implement the meta-programming proposed by @Benny upper in this thread to complement the solution, but I am still having an issue… my metaprogramming skills are not very good.

Take a look here : [Automatic aliasing of archimedeans by lrnv · Pull Request #82 · lrnv/Copulas.jl · GitHub](https://github.com/lrnv/Copulas.jl/pull/82) for the implementation and the error that I am getting. Maybe you’ll see quickly the problem

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 21, 2023, 7:33pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/35 "2023-11-21T19:33:36Z")

</div>

> [@lrnv](#):
>
> Maybe you’ll see quickly the problem

Not quickly, but maybe:

```julia
ArchimedeanCopula

```

should be

```julia
Archimedean

```

?

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 21, 2023, 7:35pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/36 "2023-11-21T19:35:01Z")

</div>

Subtypes of both all have the name structured as “SomethingGenerator” and i want to construct the “SomethingCopula” that corerspond, which is what the string manipulation does.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 21, 2023, 10:34pm UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/37 "2023-11-21T22:34:31Z")

</div>

> [@Dan](#):
>
> `S.body.body.parameters[2].name.wrapper`

Definitely an option to dig into parameters like this, but I tend to avoid internal details that could be changed in a minor revision; it’s not very often because people don’t want to change a bunch of internal base Julia on a whim. On the other hand, dispatching on subtypes is exposed as language feature.

> [@lrnv](#):
>
> Take a look here : [Automatic aliasing of archimedeans by lrnv · Pull Request #82 · lrnv/Copulas.jl · GitHub](https://github.com/lrnv/Copulas.jl/pull/82) for the implementation and the error that I am getting

It’s complaining about an undefined variable `Copulas.AMHGenerator` when you hit the metaprogramming lines. It just occurred to me that was bizarre because the module and type should not be 1 variable name, but 2. Here’s a MWE of the effect:

```julia
julia> module A end
Main.A

julia> A.X
ERROR: UndefVarError: X not defined
...
julia> var"A.X"
ERROR: UndefVarError: A.X not defined

julia> @eval $(Symbol("A.X")) = 0
0

julia> var"A.X"
0

julia> A.X
ERROR: UndefVarError: X not defined
...

```

I’m not exactly sure when this happens, but `string` on some of the types you get from `InteractiveUtils.subtypes` included the modules in the string, and baking that into a symbol makes a bizarre variable that is not the same as the type. Specifically, you can rest assured that `AMHGenerator` exists in the module `Copulas`, but `var"Copulas.AMHGenerator"` does not. You can definitely fix the string processing, but `@eval` metaprogramming typically starts with lists of explicit symbols or strings for easier discovery and handling, in your case you could start with a list of prefixes. Still, I do see the logic of deriving it at runtime from all existing types, so maybe this is a difficulty worth handling.

---

<div class="post-metadata">

**Author:** ![Dan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan/32/42581_2.png) [@Dan](https://discourse.julialang.org/u/Dan)\
**Post date:** [November 22, 2023, 2:47am UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/38 "2023-11-22T02:47:00Z")

</div>

As usaul, I’ll try to interpret the gospel of Benny:

```julia
for T in InteractiveUtils.subtypes(ZeroVariateGenerator)
    G = Symbol(last(split(string(T),'.')))
    C = Symbol(string(G)[begin:end-9]*"Copula")
    @eval begin
        const ($C){d} = ArchimedeanCopula{d,(Copulas.$G)}
        ($C)(d) = ArchimedeanCopula(d,(Copulas.$G)())
    end
end
for T in InteractiveUtils.subtypes(UnivariateGenerator)
    G = Symbol(last(split(string(T),'.')))
    C = Symbol(string(G)[begin:end-9]*"Copula")
    @eval begin
        const ($C){d,Tθ} = ArchimedeanCopula{d,(Copulas.$G){Tθ}}
        ($C)(d,θ) = ArchimedeanCopula(d,(Copulas.$G)(θ))
    end
end

```

passes the precompile phase on my machine.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 22, 2023, 4:38am UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/39 "2023-11-22T04:38:29Z")

</div>

That should work within the `Copulas.___Generator` types, but don’t canonize me 😆 I’m not even Catholic

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [November 22, 2023, 8:11am UTC](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476/40 "2023-11-22T08:11:46Z")

</div>

> [@Benny](#):
>
> It’s complaining about an undefined variable `Copulas.AMHGenerator` when you hit the metaprogramming lines. It just occurred to me that was bizarre because the module and type should not be 1 variable name, but 2. Here’s a MWE of the effect:

> [@Dan](#):
>
> ` G = Symbol(last(split(string(T),'.')))`

That was it. Thanks a lot to both of you. Nothing religious, but there should be a “compiler wizard” badge on this forum so that you can both earn it ! 🙂

Such a long journey and so many brains to solve this, its impresive how far it can get.

Edit: Maybe “Type wizard” is pedentic enough

[Previous page](https://discourse.julialang.org/t/how-to-dispatch-on-a-type-alias/106476.md?page=1)
