# Constructor of parametric types

I have the following two types. The second one is based on the first one.

``````struct RankOneMatrix{T} <: AbstractMatrix{T}
v::AbstractVector{T}
w::AbstractVector{T}
end

function Base.size(A::RankOneMatrix)
return length(A.v), length(A.w)
end

struct RankTwoMatrix{T} <: AbstractMatrix{T}
A::RankOneMatrix{T}
B::RankOneMatrix{T}
function RankTwoMatrix{T}(A::RankOneMatrix{T}, B::RankOneMatrix{T}) where T
if size(A) != size(B)
error("They have different dimensions.")
end
new(A, B)
end
end
``````

In the second type, I want the constructor to check the sizes of the two matrices are the same.
When I call ` RankTwoMatrix(RankOneMatrix(rand(3), rand(3)), RankOneMatrix(rand(3), rand(3)))`, I got the following error.

``````ERROR: LoadError: MethodError: no method matching RankTwoMatrix(::RankOneMatrix{Float64},::RankOneMatrix{Float64})
``````

I think I do have the matching method.
I’ve read the manual but still have no idea what’s going on.
Please forgive me if this is a basic question.

First note that you can construct it when you are explicit with the type parameter:

``````julia> RankTwoMatrix{Float64}(RankOneMatrix(rand(3), rand(3)), RankOneMatrix(rand(3), rand(3)));
``````

This is because when you define a custom inner constructor for a parameteric type, the outer (convenience) constructor is not automatically defined. You have to do that yourself:

``````julia> RankTwoMatrix(A::RankOneMatrix{T}, B::RankOneMatrix{T}) where T = RankTwoMatrix{T}(A::RankOneMatrix{T}, B::RankOneMatrix{T})
RankTwoMatrix

julia> RankTwoMatrix(RankOneMatrix(rand(3), rand(3)), RankOneMatrix(rand(3), rand(3)));
``````

(note the `;` are necessary as the displaying does not work with you minimal example (which is ok)).

1 Like

as @mauro3 noted above

You probably intended this:

``````struct rankTwoMatrix{T} <: AbstractMatrix{T}
A::RankOneMatrix{T}
B::RankOneMatrix{T}
function rankTwoMatrix(A::RankOneMatrix{T}, B::RankOneMatrix{T}) where T
if size(A) != size(B)
error("They have different dimensions.")
end
new{T}(A, B)
end
end
``````

defined that way, your RankOneMatrix and RankTwoMatrix will initialize – but do not try to display them `ranktwo = RankTwoMatrix(RankOneMatrix(rand(3,3)), RankOneMatrix(rand(3,3)));`

1 Like

Great, that’s the reason. Thank you.
Is there a better way that I can add the check to the constructor?
The manual outer constructor

``````RankTwoMatrix(A::RankOneMatrix{T}, B::RankOneMatrix{T}) where T = RankTwoMatrix{T}(A::RankOneMatrix{T}, B::RankOneMatrix{T})
``````

seems redundant to me.
More precisely, is it possible to define a outer constructor to check the sizes in this example?

So in the definition `foo{T}`, the `{T}` is part of the name?