# Problem with parametric composite types

**URL:** https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222
**Category:** General Usage
**Tags:** question, parametric-types, diagonal-rule
**Created:** [January 1, 2024, 3:54am UTC](https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222 "2024-01-01T03:54:55Z")
**Posts on this page:** 6
**Page:** 1

<div class="post-metadata">

### Author: ![jiang\_ming\_zhang](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jiang_ming_zhang/32/204063_2.png) [@jiang\_ming\_zhang](https://discourse.julialang.org/u/jiang_ming_zhang)
#### Post date: [January 1, 2024, 3:54am UTC](https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222/1 "2024-01-01T03:54:55Z")

</div>

I defined a type:

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

```

Then when I tried to construct an variable

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

```

I got

```julia
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?

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [January 1, 2024, 4:03am UTC](https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222/2 "2024-01-01T04:03:29Z")

</div>

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

---

<div class="post-metadata">

### Author: ![mike.ingold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike.ingold/32/203749_2.png) [@mike.ingold](https://discourse.julialang.org/u/mike.ingold)
#### Post date: [January 1, 2024, 5:14am UTC](https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222/3 "2024-01-01T05:14:59Z")

</div>

For an explanation of concrete vs abstract types see:

[https://docs.julialang.org/en/v1/manual/types/#man-abstract-types](https://docs.julialang.org/en/v1/manual/types/#man-abstract-types)

---

<div class="post-metadata">

### Author: ![mike.ingold](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mike.ingold/32/203749_2.png) [@mike.ingold](https://discourse.julialang.org/u/mike.ingold)
#### Post date: [January 1, 2024, 5:22am UTC](https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222/4 "2024-01-01T05:22:13Z")

</div>

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?

---

<div class="post-metadata">

### Author: ![Vasily\_Pisarev](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vasily_pisarev/32/7929_2.png) [@Vasily\_Pisarev](https://discourse.julialang.org/u/Vasily_Pisarev)
#### Post date: [January 1, 2024, 10:09am UTC](https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222/5 "2024-01-01T10:09:24Z")

</div>

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.

---

<div class="post-metadata">

### Author: ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)
#### Post date: [January 1, 2024, 11:13am UTC](https://discourse.julialang.org/t/problem-with-parametric-composite-types/108222/6 "2024-01-01T11:13:10Z")

</div>

> [@Vasily\_Pisarev](#):
>
> You can still manually create `Point{Any}(1, 2.0)`

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

```julia
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

```
