Parametrised Functions in 0.6.0

In 0.6.0 (released today!), using the new where syntax I’m able to define a function f as follows:

0.6.0> abstract type X{T} end

0.6.0> struct A{T} <: X{T} end

0.6.0> struct B{T} <: X{T} end

0.6.0> f(::S) where {T, S <: X{T}} = (S, T)
f (generic function with 1 method)

0.6.0> t = A{Int}()
A{Int64}()

0.6.0> f(t)
(A{Int64}, Int64)

Cool!

My question is this: is there a way to specify a function such that I can get at the type (e.g. A or B) without the parameter applied, e.g. return the value (A, Int64)?

I tried the following without success:

0.6.0> g(::S{T}) where {T, S <: X} = (S, T)
ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar

0.6.0> g(::S{T}) where {T, S <: X{T}} = (S, T)
ERROR: TypeError: Type{...} expression: expected UnionAll, got TypeVar

0.6.0> g(::S) where {T, S <: X} = (S, T)
WARNING: static parameter T does not occur in signature for g at REPL[11]:1.
The method will not be callable.
g (generic function with 1 method)

You can’t do it in dispatch (and the property is actually a little ill defined because of type aliases, etc.), but there is

julia> Base.typename(A{Int}).wrapper
A

which also has support in inference, so is efficient to use.

5 Likes

Ahh, nice! Thanks for that :slight_smile:

0.6.0> f(::S) where {T, S <: X{T}} = (Base.typename(S).wrapper, T)
f (generic function with 1 methods)

0.6.0> f(A{Int}()) === (A, Int)
true

Keno didn’t quite emphasize this enough:

It’s trivial (and fairly common) to observe cases where the .wrapper field has no relation to T. One correct way to handle a common usage of this pattern is demonstrated by the design of the similar functions in base, which demonstrates how to pull apart and recombine types correctly (using dispatch). In the grand tradition of Julia, accessing fields directly with . is usually strongly discouraged (although the reasons for this are usually left as an exercise to the reader).

1 Like