# Problem with parametric composite types

I defined a type:

``````struct Point{T}
x :: T
y :: T
end
``````

Then when I tried to construct an variable

``````b = Point(1.0, 2)
``````

I got

``````ERROR: MethodError: no method matching Point(::Float64, ::Int64)

Closest candidates are:
Point(::T, ::T) where T
@ Main REPL[2]:2
``````

The problem is, aren’t ‘Float64’ and ‘Int64’ both subtypes of ‘Any’? The construction should work if we interprete ‘T’ as ‘Any’, right?

You’re restricting x and y to have the same concrete type `T`. If you want them to be independent, do `Point{T,S}`.

2 Likes

For an explanation of concrete vs abstract types see:

https://docs.julialang.org/en/v1/manual/types/#man-abstract-types

In fairness though, I can see how this would be confusing. You should be able to construct a `Point{Real}(1.0, 2)` but I guess the compiler won’t auto infer parameterized types as abstract types?

What you see is the so-called “diagonal rule” in action.

Implicitly, Julia defines a constructor `Point(x::T, y::T) where {T} = Point{T}(x, y)`. The diagonal rule is that if a type parameter occurs multiple times in a function signature, then those occurences mean the same concrete type.

You can still manually create `Point{Any}(1, 2.0)` or add more constructors to your liking.

2 Likes

Note that this uses a different constructor from the one with the diagonal rule, which isn’t recursive despite how it looked.

``````julia> struct Point{T}
x :: T
y :: T
end

julia> Point(1, 1) # parameter inferred from arguments
Point{Int64}(1, 1)

julia> @which Point(1, 1) # diagonal rule method
Point(x::T, y::T) where T in Main at REPL[29]:2

julia> Point{Real}(1, 1.0) # manually specify parameter
Point{Real}(1, 1.0)

julia> @which Point{Real}(1, 1.0) # manual parameter method
Point{T}(x, y) where T in Main at REPL[29]:2
``````
2 Likes