# Type parameters & constructors

**URL:** <https://discourse.julialang.org/t/type-parameters-constructors/111874>\
**Category:** General Usage\
**Tags:** question, constructors\
**Created:** [March 20, 2024, 1:12pm UTC](https://discourse.julialang.org/t/type-parameters-constructors/111874 "2024-03-20T13:12:07Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![mdsalerno](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mdsalerno/32/5539_2.png) [@mdsalerno](https://discourse.julialang.org/u/mdsalerno)\
**Post date:** [March 20, 2024, 1:12pm UTC](https://discourse.julialang.org/t/type-parameters-constructors/111874/1 "2024-03-20T13:12:07Z")

</div>

I’ve defined the following type:

```julia
struct ComplexNumber{T<:Real} <: Number
    re::T
    im::T
end

```

I am having trouble understanding why the following two outer constructors behave differently:

```julia
ComplexNumber(x::Real, y::Real) = ComplexNumber(promote(x, y)...)
ComplexNumber(x::T, y::T) where {T<:Real} = ComplexNumber(promote(x, y)...)

```

The second one throws a StackOverflow error, the first one does not. The following modification makes the second constructor behave identically to the first:

```julia
ComplexNumber(x::T, y::T) where {T<:Real} = ComplexNumber{T}(promote(x, y)...)

```

How does the presence or absence of type parameters in the method signature affect access to the default (inner) constructor?

---

<div class="post-metadata">

**Author:** ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)\
**Post date:** [March 20, 2024, 1:22pm UTC](https://discourse.julialang.org/t/type-parameters-constructors/111874/2 "2024-03-20T13:22:22Z")

</div>

As far as I understand, the one that stack-overflows is just identical to the default constructor (it expect two arguments of the same type). The third one, with the type parameter, is like a different function, which an additional parameter, that here coincides with the type `T`, but could be something else.

---

<div class="post-metadata">

**Author:** ![sbuercklin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sbuercklin/32/15728_2.png) [@sbuercklin](https://discourse.julialang.org/u/sbuercklin)\
**Post date:** [March 20, 2024, 1:26pm UTC](https://discourse.julialang.org/t/type-parameters-constructors/111874/3 "2024-03-20T13:26:03Z")

</div>

The issue is your second method states that `x, y` have the same type `T`, which looks identical to the default constructor for `ComplexNumber`. When you promote two numbers of type `T`, you get back two numbers of type `T`, which dispatches back to the same method. Adding unique type parameters for `x` and `y` both makes it work:

```julia
julia> ComplexNumber(r::S, i::T) where {S<:Real, T<:Real} = ComplexNumber(promote(r, i)...)

julia> ComplexNumber(1, 2.0)
ComplexNumber{Float64}(1.0, 2.0)

```

The last one you showed disambiguates because there is a difference between `ComplexNumber` and `ComplexNumber{T}`. You haven’t defined a method for `ComplexNumber{T}` so that dispatches to the default constructor method with the type parameters.

---

<div class="post-metadata">

**Author:** ![ettersi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ettersi/32/6829_2.png) [@ettersi](https://discourse.julialang.org/u/ettersi)\
**Post date:** [March 21, 2024, 1:55am UTC](https://discourse.julialang.org/t/type-parameters-constructors/111874/4 "2024-03-21T01:55:10Z")

</div>

> [@mdsalerno](#):
>
> How does the presence or absence of type parameters in the method signature affect access to the default (inner) constructor?

The `{T}` in `ComplexNumber{T}(args...)` is not part of the method signature, it’s part of the function name. At the language level, `ComplexNumber(...)` and `ComplexNumber{T}(...)` are two independent functions that just so happen to share a part of their names. This little demo might help appreciate this:

```julia
julia> struct Foo{T}
           x::T
           
           # Explicit inner constructor to eliminate the default outer constructor
           Foo{T}(x) where {T} = new(x)
       end

julia> methods(Foo{Int}) # This is the inner constructor we defined above 
# 1 method for type constructor:
 [1] Foo{T}(x) where T
     @ REPL[2]:5

julia> methods(Foo) # Doesn't list the inner constructor because this is a different function
# 0 methods for type constructor

```

* * *

What is happening in your example is that this constructor

```julia
ComplexNumber(x::T, y::T) where {T<:Real} = ComplexNumber(promote(x, y)...)

```

dispatches to `ComplexNumber`, and the only method of this function is the `ComplexNumber(x::T, y::T) where {T<:Real}` which we started from; hence you get infinite recursion.

By contrast, this construct

```julia
ComplexNumber(x::T, y::T) where {T<:Real} = ComplexNumber{T}(promote(x, y)...)

```

dispatches to `ComplexNumber{T}` and therefore ends up calling the implicit inner constructor.
