# No automatic type promotion for parametric structs

**URL:** <https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664>\
**Category:** Internals & Design\
**Created:** [June 10, 2021, 9:57am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664 "2021-06-10T09:57:27Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![lungben](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lungben/32/12314_2.png) [@lungben](https://discourse.julialang.org/u/lungben)\
**Post date:** [June 10, 2021, 9:57am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/1 "2021-06-10T09:57:27Z")

</div>

When using different (but convertible) types in a constructor, for “standard” structs the types get converted automatically, e.g.

```julia
struct Struct1
    x:: Float64
    y
end

s1b = Struct1(5, 1) # output: Struct1b(5.0, 1)

```

However, this is not done if the struct has a type parameter (even if this parameter is for a different field), instead I get a MethodError:

```julia
struct Struct2{T}
    x:: Float64
    y:: T
end

s2b = Struct2(5, 1) # MethodError, I would expect Struct2{Int64}(5.0, 1)

s2c = Struct2(5.0, 1) # this works, output: Struct2{Int64}(5.0, 1)

```

This behavior is confusing for me, I would expect that type promotion is also done for parametric structs. Or is there a good reason for it which I am not aware of?

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [June 10, 2021, 10:53am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/3 "2021-06-10T10:53:05Z")

</div>

I think it isn’t about automatic promotion, but rather about  
what constructors are automatically provided.

In particular that the constructors provided for a `UnionAll` (like `Struct2` i.e. `Struct2{T} where T`]) don’t have one that calls convert.

```julia
julia> methods(Struct1) # method of concrete type
# 2 methods for type constructor:
[1] Struct1(x::Float64, y) in Main at REPL[5]:2
[2] Struct1(x, y) in Main at REPL[5]:2

julia> methods(Struct2) # method of the UnionAll 
# 1 method for type constructor:
[1] Struct2(x::Float64, y::T) where T in Main at REPL[1]:2

julia> methods(Struct2{Int}) # method of concrete type
# 1 method for type constructor:
[1] Struct2{T}(x, y) where T in Main at REPL[1]:2

```

We can see if we pass the type parameter to Struct2 so we have a concrete type the convert does happen

```julia
julia> Struct2{Int}(5, 1.)
Struct2{Int64}(5.0, 1)

```

So question is kind why isn’t there a constructor  
`Struct2(a, b::B) where B = Struct2{B}(a, b)`

If we define that then it works:

```julia
julia> Struct2(a, b::B) where B = Struct2{B}(a, b)
Struct2

julia> Struct2(5,1)
Struct2{Int64}(5.0, 1)

```

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [June 10, 2021, 10:53am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/4 "2021-06-10T10:53:51Z")

</div>

I was just replying the same, but your is way better, so thanks! I still want to know the answer to your question, though:

_Why isn’t there an automatic contructor that does this?_

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [June 16, 2021, 10:26am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/5 "2021-06-16T10:26:14Z")

</div>

I think this could be a good discussion for a new feature, in case it is possible. In case this is intentional and not possible, it might be a good place for an answer.

# Previous considerations

There is a discussion for the case where two arguments to the struct are parametric in [Types](https://docs.julialang.org/en/v1/manual/types/#Parametric-Types), whether bi-parametric or single-parametric. It says that this constructor is not provided by default because there could be ambiguity between the possible extrapolated types. However, this is not always the case.

# Counter example (single parameter)

```julia-auto
struct single_param{T}
r::Float64
s::T
end

```

In this case, the type could be easily extrapolated from the variables passed with a single parametric method.

```julia-auto
# Current status
julia> prueba(3,9)
ERROR: MethodError: no method matching single_param(::Int64, ::Int64)
Closest candidates are:
  single_param(::Float64, ::T) where T at REPL[1]:2

# Solution
julia> single_param(r, s::T) where {T} = single_param{T}(r, s)
single_param

julia> single_param(3,9)
single_param{Int64}(3.0, 9)

julia> single_param(3,"4")
single_param{String}(3.0, "4")

```

# Counter example (multi parameter)

```julia-auto
struct multi_param{T, U}
q::Float64
r::T
s::U
end

```

Even in this case, the types could be extrapolated from the variables passed.

```julia-auto
# Current status
julia> multi_param(3,9,"7")
ERROR: MethodError: no method matching multi_param(::Int64, ::Int64, ::String)
Closest candidates are:
  multi_param(::Float64, ::T, ::U) where {T, U} at REPL[8]:2

# Solution
julia> multi_param(q, r::T, s::U) where {T, U} = multi_param{T, U}(q, r, s)
multi_param

julia> multi_param(3,9,7im)
multi_param{Int64, Complex{Int64}}(3.0, 9, 0 + 7im)

julia> multi_param(3,9,"t")
multi_param{Int64, String}(3.0, 9, "t")

```

# Conclusions

I take the liberty of summoning @StefanKarpinski in case there is a reason for this (sorry if it is already somewhere, I cannot find it in the docs).

---

<div class="post-metadata">

**Author:** ![oxinabox](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oxinabox/32/206603_2.png) [@oxinabox](https://discourse.julialang.org/u/oxinabox)\
**Post date:** [June 16, 2021, 10:46am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/6 "2021-06-16T10:46:09Z")

</div>

Strong recommend moving this to a GitHub issue.  
That is where feature requests are discussed for formally.

---

<div class="post-metadata">

**Author:** ![lungben](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lungben/32/12314_2.png) [@lungben](https://discourse.julialang.org/u/lungben)\
**Post date:** [June 16, 2021, 10:47am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/7 "2021-06-16T10:47:30Z")

</div>

Thanks for your feedback!  
I’ll create an issue for it.

Edit: done - [https://github.com/JuliaLang/julia/issues/41241](https://github.com/JuliaLang/julia/issues/41241)

---

<div class="post-metadata">

**Author:** ![nandoconde](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nandoconde/32/19497_2.png) [@nandoconde](https://discourse.julialang.org/u/nandoconde)\
**Post date:** [June 16, 2021, 11:45am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/8 "2021-06-16T11:45:23Z")

</div>

> [@nandoconde](#):
>
> Counter example (multi parameter)

Thanks! I was wary of doing it because it may already have an explanation and I didn’t want to add more Issues (it is very crowded there).

---

<div class="post-metadata">

**Author:** ![jakobnissen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jakobnissen/32/13477_2.png) [@jakobnissen](https://discourse.julialang.org/u/jakobnissen)\
**Post date:** [June 16, 2021, 11:50am UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/9 "2021-06-16T11:50:54Z")

</div>

This is a duplicate of [Autogenerate `(::Type{Foo})(x::T, y) where T` constructor for type Foo{T} · Issue #35053 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/35053), which has bitten people repeatedly before.

---

<div class="post-metadata">

**Author:** ![lungben](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lungben/32/12314_2.png) [@lungben](https://discourse.julialang.org/u/lungben)\
**Post date:** [June 16, 2021, 1:12pm UTC](https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/10 "2021-06-16T13:12:39Z")

</div>

Thanks for mentioning it, I have not found it in my searches before.  
I found this behavior especially problematic together with `Base.@kwdef` if (at least) one of the fields is parametric, e.g. if it is a `Function` (which is an abstract type, making this type parametric brings back type stability).
