The following code works well in v0.6.4 but fails in v1.0:
module Scratch
using StaticArrays
abstract type AbstractX end
struct Foo{E<:AbstractX}
v::Vector{E}
function Foo{E}(v::Vector{E}) where {E}
new(copy(v))
end
end
struct ConcreteX{N,T} <: AbstractX
w::SVector{N, T}
function ConcreteX{N,T}(w::SVector{N, T}) where {N,T}
new(w)
end
end
function ConcreteX(w::SVector{N, T}) where {N,T}
ConcreteX{N,T}(w)
end
const Bar{N,T}=Foo{ConcreteX{N,T}}
e1= ConcreteX(@SVector [1, 2])
e2= ConcreteX(@SVector [3, 4])
Bar([e1, e2])
end
The error message is:
ERROR: LoadError: MethodError: no method matching Main.Scratch.Foo{Main.Scratch.ConcreteX{N,T} where T} where N(::Array{Main.Scratch.ConcreteX{2,Int64},1})
(at the line 29). Update
Explicit type specification
Bar{2,Int}([e1, e2])
is a possible workaround. But I still do no see how one can help Julia to infer the type parameters of Bar.
Type inference has nothing to do with this, it’s more of a subtyping question. You probably want something like:
module Scratch
using StaticArrays
abstract type AbstractX end
struct Foo{E<:AbstractX}
v::Vector{E}
function (::Type{<:Foo})(v::Vector{E}) where {E}
new{E}(copy(v))
end
end
struct ConcreteX{N,T} <: AbstractX
w::SVector{N, T}
function ConcreteX{N, T}(w::SVector{N, T}) where {N,T}
new{N,T}(w)
end
end
function ConcreteX(w::SVector{N, T}) where {N,T}
ConcreteX{N,T}(w)
end
const Bar{N,T}=Foo{ConcreteX{N,T}}
e1= ConcreteX(@SVector [1, 2])
e2= ConcreteX(@SVector [3, 4])
x = Bar([e1, e2])
end
Yes, new{ } is described in the manual chapter on constructors.
The key to understanding this is that there’s no real distinction between a constructor and a “callable type”. Every method definition can be written two ways: either by specifying the (singleton) instance of the called thing, or by specifying its type. So function f(x) can also be written as function (::typeof(f))(x). (Detail: the second form requires f to be assigned already.) For types, it looks like function Int(x) or function (::Type{Int})(x) but the idea is the same.
It’s quite possible the manual chapter should be rewritten not to refer to “inner” and “outer” constructors. The only distinctions that matter are (1) what type is the method defined for, and (2) is it written inside the struct block, giving it access to new. These two are completely orthogonal.
Thank you, this clarifies the situation. As for the manual, I guess that the issue is larger than the story of “inner” and “outer” constructors. The very notion of constructor seems to be quite different in Julia from what people are used to in other languages. As far as I understand, in Julia it is not a hard-coded feature of the language, but rather an idiom (a particular case of a “callable thing”).