Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Generic constructors for subtypes of an abstract type

Tags:

types

julia

I have a type AbstractT and for each subtype I want to define a constructor T(x::Tuple), but I can't find a generic way to do it because everything in Julia like this uses dispatch, but I cannot dispatch on the constructor since the name of the constructor matches the type and so each constructor is a different function. i.e. it would work if there was a

construct{T<:AbstractT}(::Type{T},x::Tuple) = # Define all the constructors

and I do that internally, but then it doesn't work nicely with other packages which will call T(x) directly and error. Is Julia using dispatch under the hood in some way that I could tap into?

like image 412
Chris Rackauckas Avatar asked Oct 20 '16 16:10

Chris Rackauckas


1 Answers

It's a little funny-looking, but you actually can dispatch on the type of the function itself! In the case of a constructor, the function is the type in question:

julia> abstract type AbstractT end

julia> struct ConcreteT{T} <: AbstractT; end

julia> (::Type{ConcreteT{Int}})() = 1

julia> (::Type{ConcreteT{Float64}})() = 2

julia> ConcreteT{Int}()
1

julia> ConcreteT{Float64}()
2

You can even use type parameters… they go in the normal place after the function name and the argument list:

julia> (::Type{ConcreteT{T}})() where {T<:Number} = 3


julia> (::Type{ConcreteT{T}})() where {T<:AbstractArray} = 4

julia> ConcreteT{Float32}()
3

julia> ConcreteT{UnitRange{Int}}()
4

You can even do this with your abstract types, but watch out:

julia> (::Type{T})() where {T<:AbstractT} = 5

julia> ConcreteT{String}()
ConcreteT{String}()

julia> AbstractT()
5

Why didn't the abstract constructor work for ConcreteT{String}? Recall that Julia creates constructors for you… and since this is just dispatch, those constructors are more specific and take precedence:

julia> methods(ConcreteT{String})
# 2 methods for type constructor:
[1] (::Type{ConcreteT{T}})() where T in Main at REPL[2]:1
[2] (::Type{T})() where T<:AbstractT in Main at REPL[12]:1

So you need to be careful when using this capability; it'll only work if it doesn't clash with your leaf constructors:

julia> (::Type{T})(x) where {T<:AbstractT} = x

julia> ConcreteT{String}(6)
6

julia> ConcreteT{Int}(7)
7
like image 137
mbauman Avatar answered Sep 28 '22 19:09

mbauman