# Default parametric constructors of composite types

**URL:** <https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329>\
**Category:** Internals & Design\
**Tags:** proposal\
**Created:** [January 31, 2019, 6:18pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329 "2019-01-31T18:18:25Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [January 31, 2019, 6:18pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/1 "2019-01-31T18:18:25Z")

</div>

Observe the following code under Julia 1.1

```julia
julia> struct A{T}
       a::T
       b::Vector{Int}
       end

julia> A(1, [1])
A{Int64}(1, [1])

julia> A(1, [1,2])
A{Int64}(1, [1, 2])

julia> A(1, 1:2)
ERROR: MethodError: no method matching A(::Int64, ::UnitRange{Int64})
Closest candidates are:
  A(::T, ::Array{Int64,1}) where T at REPL[1]:2
Stacktrace:
 [1] top-level scope at none:0

julia> A{Int}(1, 1:2)
A{Int64}(1, [1, 2])

julia> A(a::T, b) where {T} = A{T}(a, b)
A

julia> A(1, 1:2)
A{Int64}(1, [1, 2])

```

The problem is that the default constructor `A(a,b)` does not perform any automatic conversions although the constructor `A{Int}(a::Int,b)` does perform an automatic conversion of `b` to an appropriate type. Also if the `struct` is not parametric then also automatic conversion is performed.

I find it a bit inconsistent. Was it considered to allow for automatic conversion of non-parametric fields in parametric type? Or maybe there are some problems if this were allowed?

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 31, 2019, 8:15pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/2 "2019-01-31T20:15:52Z")

</div>

I think the question is: how does Julia know how to convert from `UnitRange{Int}` to `Vector{Int}`?

---

<div class="post-metadata">

**Author:** ![dpsanders](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dpsanders/32/3573_2.png) [@dpsanders](https://discourse.julialang.org/u/dpsanders)\
**Post date:** [January 31, 2019, 8:16pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/3 "2019-01-31T20:16:26Z")

</div>

Though I see that in this case there is

```julia
julia> Vector{Int}(1:3)
3-element Array{Int64,1}:
 1
 2
 3

```

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [January 31, 2019, 8:24pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/4 "2019-01-31T20:24:31Z")

</div>

> [@dpsanders](#):
>
> how does Julia know how to convert from `UnitRange{Int}` to `Vector{Int}` ?

Julia knows this conversion. The problem is that the method signature generated for a default constructor is too specific, see here:

```julia
julia> struct A{T}
              a::T
              b::Vector{Int}
              end

julia> methods(A)
# 1 method for generic function "(::Type)":
[1] (::Type{A})(a::T, b::Array{Int64,1}) where T in Main at REPL[1]:2

julia> methods(A{Int})
# 1 method for generic function "(::Type)":
[1] (::Type{A{T}})(a, b) where T in Main at REPL[1]:2

```

and you see that the signature for `b` in the first case (constructor without a parameter) is restricted, but it is not restricted for a constructor with a parameter.

---

<div class="post-metadata">

**Author:** ![Nosferican](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nosferican/32/9275_2.png) [@Nosferican](https://discourse.julialang.org/u/Nosferican)\
**Post date:** [January 31, 2019, 10:36pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/5 "2019-01-31T22:36:44Z")

</div>

I think it is actually consistent with method dispatch. The default constructor defines a specific method, but automatic conversion would mess up with type dispatch. The default constructor is just defining a method just like any other function.

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [January 31, 2019, 10:47pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/6 "2019-01-31T22:47:42Z")

</div>

> [@Nosferican](#):
>
> automatic conversion would mess up with type dispatch.

Where it would mess up?

My question is why we have

```julia
(::Type{A})(a::T, b::Array{Int64,1}) where T

```

and not

```julia
(::Type{A})(a::T, b) where T

```

automatically defined method signature.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [January 31, 2019, 10:52pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/7 "2019-01-31T22:52:49Z")

</div>

Yeah, I agree with you here. The key thing is that without any type parameters, we get two methods:

```julia
julia> struct B
           a::Int
           b::Float64
       end

julia> methods(B)
# 2 methods for generic function "(::Type)":
[1] B(a::Int64, b::Float64) in Main at REPL[4]:2
[2] B(a, b) in Main at REPL[4]:2

```

The first is the actual constructor, the second is converts arguments appropriately.

With a type parameter, we don’t get the converting method defined on `A` — it’s only defined on `A{T}`.

```julia
julia> struct A{T}
           a::T
           b::Int
           c::Float64
       end

julia> methods(A)
# 1 method for generic function "(::Type)":
[1] (::Type{A})(a::T, b::Int64, c::Float64) where T in Main at REPL[1]:2

```

---

<div class="post-metadata">

**Author:** ![bkamins](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bkamins/32/208538_2.png) [@bkamins](https://discourse.julialang.org/u/bkamins)\
**Post date:** [January 31, 2019, 11:05pm UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/8 "2019-01-31T23:05:43Z")

</div>

This is my point. In general it is possible that in complex signatures it might be non-trivial/impossible to derive type parameters in a “converting” constructor unambiguously, but already the rule:

- if a field type is parameterized in any way (i.e. depends on a type parameter) then it is not converted but its type passed exactly as-is to the constructor method signature;
- if a field type does not depend on any parameter of the type then it is converted;

would improve things and probably would cover most use-cases in practice.

---

<div class="post-metadata">

**Author:** ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)\
**Post date:** [February 1, 2019, 8:38am UTC](https://discourse.julialang.org/t/default-parametric-constructors-of-composite-types/20329/9 "2019-02-01T08:38:04Z")

</div>

x-ref: [https://github.com/JuliaLang/julia/issues/17186#issuecomment-286300768](https://github.com/JuliaLang/julia/issues/17186#issuecomment-286300768)
