Parametrised Functions in 0.6.0

#1

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)
``````

#2

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.

#3

Ahh, nice! Thanks for that

``````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
``````

#4

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).