<p dir="auto">See discussion in <a href="https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/1" rel="nofollow">https://discourse.julialang.org/t/no-automatic-type-promotion-for-parametric-structs/62664/1</a></p>
<p dir="auto">When using different (but convertible) types in a constructor, for "standard" structs the types get converted automatically, e.g.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="struct Struct1
    x:: Float64
    y
end

s1b = Struct1(5, 1) # output: Struct1b(5.0, 1)"><pre class="notranslate"><code class="notranslate">struct Struct1
    x:: Float64
    y
end

s1b = Struct1(5, 1) # output: Struct1b(5.0, 1)
</code></pre></div>
<p dir="auto">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:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="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)"><pre class="notranslate"><code class="notranslate">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)
</code></pre></div>
<p dir="auto">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?</p>
<p dir="auto">Consider a definition of a parameter-less struct:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="struct Bar
    x::Int
    y::Float64
end"><pre class="notranslate"><code class="notranslate">struct Bar
    x::Int
    y::Float64
end
</code></pre></div>
<p dir="auto">This creates two constructors: A fully specified <code class="notranslate">Bar(x::Int64, y::Float64)</code> and a fully <em>un</em>specified <code class="notranslate">Bar(x, y)</code>. The latter is very convenient because you can just do <code class="notranslate">Bar(1, 1)</code> and it will automatically convert.</p>
<p dir="auto">For a simple struct with a type param, we have something similar:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="struct Baz{T}
    x::T
end"><pre class="notranslate"><code class="notranslate">struct Baz{T}
    x::T
end
</code></pre></div>
<p dir="auto">creates the specified <code class="notranslate">(::Type{Baz{T}})(x) where T</code> and the unspecified <code class="notranslate">(::Type{Baz})(x::T) where T</code>. The latter handily allows you to call <code class="notranslate">Baz(1.0)</code> and get exactly what you expect.</p>
<p dir="auto">However, if you make:</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="struct Foo{T}
    x::T
    y::Float64
end"><pre class="notranslate"><code class="notranslate">struct Foo{T}
    x::T
    y::Float64
end
</code></pre></div>
<p dir="auto">You get <code class="notranslate">(::Type{Foo{T}})(x, y) where T</code> and <code class="notranslate">(::Type{Foo})(x::T, y::Float64) where T</code>. But there is no equivalent convenience method <code class="notranslate">(::Type{Foo})(x::T, y) where T</code> that allows you to do <code class="notranslate">Foo(1, 1)</code> and have it work. That would be nice to have though.</p>
<p dir="auto">This was raised by <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/arnavs/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/arnavs">@arnavs</a> on Slack who found it counterintuitive.</p>