# Inner contructor with parametric type

**URL:** <https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170>\
**Category:** New to Julia\
**Created:** [January 9, 2020, 9:45pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170 "2020-01-09T21:45:51Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [January 9, 2020, 9:45pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/1 "2020-01-09T21:45:51Z")

</div>

I am trying to create a structure where parameter types can either be given explicitly or are inferred automatically from the arguments. However, I also would like to define the inner constructor method, such as in the following example:

```julia
struct A{T}
    x :: T
    A{T}(a) where T = new(a^2)
end

```

When I explicitly give the type, it works fine, e.g.,

```julia
julia> A{Float64}(2)
A{Float64}(4.0)

```

However, when the type is not explicitly given, it raises the following error:

```julia
julia> A(2)
ERROR: MethodError: no method matching A(::Int64)
Stacktrace:
 [1] top-level scope at none:0

```

What do I need to do in order to be able to have parametric types that can be inferred or given explicitly with an explicit inner constructor?

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 9, 2020, 10:20pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/2 "2020-01-09T22:20:06Z")

</div>

Providing a simple parametric (outer) constructor that only infers the type should be enough here. For example:

```julia
struct A{T}
    x :: T
    y :: T
    A{T}(a) where T = new(a, a^2)
end

A(x::T) where {T} = A{T}(x)

```

yields:

```julia
julia> A{Float64}(2)
A{Float64}(2.0, 4.0)

julia> A(2)
A{Int64}(2, 4)

```

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [January 9, 2020, 10:47pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/3 "2020-01-09T22:47:17Z")

</div>

Thank you very much for your reply. But what about if I have multiple input arguments of different numeric types and the type can either be inferred from the calculation ou explicitly given, as in the following example?

```julia
julia> struct A{T}
           x :: T
           A{T}(a, b, c) where T = new(a*b*c)
       end

julia> A{Float64}(1.0, 2, 3)
A{Float64}(6.0)

julia> A(1.0, 2, 3)
ERROR: MethodError: no method matching A(::Float64, ::Int64, ::Int64)
Stacktrace:
 [1] top-level scope at none:0

```

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [January 9, 2020, 11:00pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/4 "2020-01-09T23:00:56Z")

</div>

I found the following solution but I find it a bit inelegant (or it’s probably not…):

`(a::T1, b::T2, c::T3) where {T1, T2, T3} = A{promote_type(T1, T2, T3)}(a, b, c)`

Is there a simpler solution?

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 9, 2020, 11:08pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/5 "2020-01-09T23:08:15Z")

</div>

If the type of the result of your expression looks like a promotion of the operands types, then `promote_type` can help you determine the correct type in the outer constructor:

```julia
struct A{T}
    x :: T
    A{T}(a, b, c) where T = new(a*b*c)
end

function A(args...)
    T = promote_type(typeof.(args)...)
    A{T}(args...)
end

```

Yielding:

```julia
julia> A{Float64}(2.0, 3, 4)
A{Float64}(24.0)

julia> A(2.0, 3, 4)
A{Float64}(24.0)

```

_[EDIT: it looks like our posts crossed and you thought about that as well. I’m only keeping this first part here for the sake of consistency with the second part below]_

  

* * *
  

Now, in more complex cases, you might want to let the compiler perform more complex inference. One way to do it would look something like:

```julia
__b_expr(a, b, c) = a * b / c

struct B{T}
    x :: T
    B{T}(a, b, c) where T = new(__b_expr(a, b, c))
end

function B(args...)
    T = typeof(__b_expr(args...))
    B{T}(args...)
end

```

Using `promote_type` in this case would not have promoted the result of the division like it should have, but relying on the compiler make the code behave like expected:

```julia
julia> B{Float64}(2, 3, 4)
B{Float64}(1.5)

julia> B(2, 3, 4)
B{Float64}(1.5)

julia> B(2, BigInt(3), 4)
B{BigFloat}(1.5)

```

It should even be statically inferred in most cases:

```julia
julia> @code_warntype B(2, BigInt(3), 4)
Variables
  args::Tuple{Int64,BigInt,Int64}
  T::Type{BigFloat}

Body::B{BigFloat}
[...]

```

I do not know of any more elegant way to do this, but there might exist some…

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [January 9, 2020, 11:39pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/6 "2020-01-09T23:39:58Z")

</div>

Thank you very much. Your reply was really very useful.

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [January 9, 2020, 11:43pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/7 "2020-01-09T23:43:21Z")

</div>

Just one more question, please. In your example using `__b_expr(a, b, c)`, if the type is not explicitly given, doesn’t the calculation of `a * b / c` is performed twice?

In the actual code that I am writing the calculations are much larger, performed in many lines, using vectors.

---

<div class="post-metadata">

**Author:** ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)\
**Post date:** [January 9, 2020, 11:58pm UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/8 "2020-01-09T23:58:40Z")

</div>

If the compiler is able to infer the type of `__b_expr(args...)`, the type will be computed statically, and the expression will really be computed only once, by the inner constructor. This is for example shown above by `@warntype` being able to statically determine the correct parametric type.

However, if the return type of your computations is not inferred for whatever reason (type unstability for instance), then you’re right: this kind of technique would involve computing twice the same result (and also rely on the assumption that we get at least the same output type both times).

---

<div class="post-metadata">

**Author:** ![aaraujo71](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaraujo71/32/10635_2.png) [@aaraujo71](https://discourse.julialang.org/u/aaraujo71)\
**Post date:** [January 10, 2020, 12:44am UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/9 "2020-01-10T00:44:35Z")

</div>

Sorry to bother you again.

In my case I use the following function to infer the type (I use `Γ` for type since I use `T` for temperature):

```julia
function Emis(args...)
    Γ = eltype(emis_vals(args...))
    return Emis{Γ}(args...)
end

```

Running `@code_warntype Emis(6, [1, 20], [0.4, 0.8], 0.5, BigFloat(10))`, I get the following output:

```julia
Variables
  #self#::Type{Emis}
  args::Tuple{Int64,Array{Int64,1},Array{Float64,1},Float64,BigFloat}
  Γ::Type{BigFloat}

Body::Emis{BigFloat}
1 ─ %1 = Core._apply(Main.emis_vals, args)::Array{BigFloat,1}
│ (Γ = Main.eltype(%1))
│ %3 = Core.apply_type(Main.Emis, Γ::Core.Compiler.Const(BigFloat, false))::Core.Compiler.Const(Emis{BigFloat}, false)
│ %4 = Core._apply(%3, args)::Emis{BigFloat}
└── return %4

```

Is my code inferring the type statically (without doing the computations twice)?

Thank you again for your help.

---

<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 10, 2020, 11:52am UTC](https://discourse.julialang.org/t/inner-contructor-with-parametric-type/33170/10 "2020-01-10T11:52:14Z")

</div>

It does infer the type statically, but, I guess, it does call `emis_vals`. It has to, because `emis_vals` is called on mutable arguments. For all the compiler knows, it may have been called for side effects.
