Parametric type internal constructor

I am a bit confused about type annotations in the internal constructor of a parametric type.

Are there differences in the following 4 approaches in terms of JIT output efficiency and execution efficiency?

immutable MyType{T} x::T MyType{T}(x::T) = new{T}(x + x) end immutable MyType{T} x::T MyType(x::T) = new{T}(x + x) end immutable MyType{T} x::T MyType(x::T) = new(x + x) end immutable MyType{T} x::T MyType{T}(x::T) = new(x + x) end 

They all work for x = MyType{Int}(1)

+6
source share
2 answers

a "canonical" way of defining an internal constructor of a parametric type:

 immutable MyType{T<:"specific abstract type"} x::T MyType(x) = new(x + x) end 

instead of declaring a common function MyType(x) , which can take arbitrary values, julia automatically determines the set of specific MyType(x::T) , where T<:"specific abstract type" . therefore your last two examples are equivalent to this.

as we know, the functionality of new is to create new objects, it is not necessary to make it parametric, because we have already applied restrictions before we call this function.

FYI, the default constructor is different from the one described above:

 immutable MyType{T<:"specific abstract type"} x::T end 

here, julia does one more thing: define an external constructor:

MyType{T<:"specific abstract type"}(x::T) = MyType{T}(x)

 julia> methods(MyType) 3-element Array{Any,1}: call{T<:Integer}(::Type{MyType{T<:Integer}}, x::T<:Integer) at none:2 call{T}(::Type{T}, arg) at essentials.jl:56 call{T}(::Type{T}, args...) at essentials.jl:57 

a

 julia> immutable MyType{T<:Integer} x::T MyType(x) = new(x) end julia> methods(MyType) 2-element Array{Any,1}: call{T}(::Type{T}, arg) at essentials.jl:56 call{T}(::Type{T}, args...) at essentials.jl:57 

this means that you may need to define this external constructor manually if you want to create your own internal constructor.

+2
source

I declared MyType using the above 4 approaches:

 immutable MyType1{T} x::T MyType1{T}(x::T) = new{T}(x + x) end immutable MyType2{T} x::T MyType2(x::T) = new{T}(x + x) end immutable MyType3{T} x::T MyType3{T}(x::T) = new(x + x) end immutable MyType4{T} x::T MyType4(x::T) = new(x + x) end 

then printed my LLVM bytecode: code_llvm(MyType1{Int},Int) and compared the outputs, they are exactly the same, so I think there is no difference between the 4 approaches.

+1
source

All Articles