Parametric Constructor in Julia 0.6


#1

I have a hard time defining a constructor for a parametric type

struct Point{T}
   x::T
   y::T
   Point{T}(x,y) where {T} = new(x,y)
end

Point(0.0, 0.0)
# ERROR: MethodError: no method matching Point(::Float64, ::Float64)

What am I missing?


#2

The constructor you’ve defined (Point{T}(x, y)) is invoked when the T parameter is explicitly given, like this:

Point{Float64}(0.0, 0.0)

The reason this is happening is that by defining your own inner constructor, you’ve overwritten the default inner constructor for your type. You could fix this by defining a more flexible inner constructor:

struct Point{T}
  x::T
  y::T
  Point(x::T, y::T) where {T} = new{T}(x, y)  # called with Point(x, y)
  Point{T}(x, y) where {T} = new{T}(x, y)     # called with Point{T}(x, y)
end

julia> Point(0.0, 0.0)
Point{Float64}(0.0, 0.0)

julia> Point{Int}(0.0, 0.0)
Point{Int64}(0, 0)

#3

Is there any advantage/difference between what you have posted and

struct Point{T}
  x::T
  y::T
  Point{T}(x, y) where {T} = new{T}(x, y)     # called with Point{T}(x, y)
end
Point(x::T, y::T) where {T} = Point{T}(x, y)  # called with Point(x, y)


#4

@musm actually I think your version is more standard, but I’m not super clear on the distinction.


#5

Same for dispatch. Putting it in the type def allows access to new keyword to construct the object without proxy though another constrictor


#6

I’d prefer the inner constructor to avoid that tiny code repetition (new vs Point).


#7

Wouldn’t the compiler inline this anyway?

From the perspective of coding style, inner constructors are generally justified when they provide something extra (incomplete initialization, checking consistency), in which case it may be better to pack the extra functionality in a few inner constructors (ideally one), and call that.


#8

Inlining isn’t the issue at all. Having access to new means that you are not constraint by the signature of defined constructors and can construct the object directly.