I see why itâs tricky, the earlier advice to use the REPL printout would mislead:
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> 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> 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}