# Best practices for defining inner constructors for parametric types

**URL:** <https://discourse.julialang.org/t/best-practices-for-defining-inner-constructors-for-parametric-types/106494>\
**Category:** General Usage\
**Tags:** parametric-types, constructors, best-practices\
**Created:** [November 20, 2023, 10:21pm UTC](https://discourse.julialang.org/t/best-practices-for-defining-inner-constructors-for-parametric-types/106494 "2023-11-20T22:21:20Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![brainandforce](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/brainandforce/32/211054_2.png) [@brainandforce](https://discourse.julialang.org/u/brainandforce)\
**Post date:** [November 20, 2023, 10:21pm UTC](https://discourse.julialang.org/t/best-practices-for-defining-inner-constructors-for-parametric-types/106494/1 "2023-11-20T22:21:20Z")

</div>

In much of my development, I have parametric types that need inner constructors to be defined with some validation code:

```julia
struct MyType{T<:Number}
    a::T
    b::T
    # Inner constructor goes here.
end

```

However, I’m not sure whether there’s a reason we should prefer to define the inner constructor with or without type parameters. Either we could use type parameters:

```julia
function MyType{T}(a, b) where T
    # Validation logic goes here
    return new(a,b)
end

```

Or we could define the inner constructor without them, if we can infer what `T` should be from the argument types:

```julia
function MyType(a, b)
    T = promote_type(typeof(a), typeof(b))
    # Validation logic goes here
    return new{T}(a, b)
end

```

With either case, to get both a constructor for `MyType` and `MyType{T}`, we’d have to define the missing method as an outer constructor. Is there a broad, overarching reason to implement one over the other as the inner constructor? Or should it be handled on a case-by-case basis? Or does it matter at all?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [November 20, 2023, 10:57pm UTC](https://discourse.julialang.org/t/best-practices-for-defining-inner-constructors-for-parametric-types/106494/2 "2023-11-20T22:57:51Z")

</div>

In this example, it’ll almost work the same, only differences being which of the [default constructors](https://docs.julialang.org/en/v1/manual/constructors/#Parametric-Constructors) you have explicitly replaced.

Method type parameters are useful for enforcing that the call provides a value for the parameter, enforcing that multiple arguments share a parameter in some way, or forcing specialization on arguments that aren’t always automatically (`Function`, types, `Vararg`). If you don’t need those, you don’t have to use them.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 20, 2023, 11:05pm UTC](https://discourse.julialang.org/t/best-practices-for-defining-inner-constructors-for-parametric-types/106494/3 "2023-11-20T23:05:34Z")

</div>

> [@Benny](#):
>
> which of the [default constructors](https://docs.julialang.org/en/v1/manual/constructors/#Parametric-Constructors) you have explicitly replaced

Pretty sure that defining an inner constructor prevents any default constructors from being defined.

---

<div class="post-metadata">

**Author:** ![nsajko](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nsajko/32/221187_2.png) [@nsajko](https://discourse.julialang.org/u/nsajko)\
**Post date:** [November 20, 2023, 11:31pm UTC](https://discourse.julialang.org/t/best-practices-for-defining-inner-constructors-for-parametric-types/106494/4 "2023-11-20T23:31:57Z")

</div>

In Julia the convention ([sadly](https://github.com/JuliaLang/julia/issues/42372) not enforced by the compiler) is that, for any type `S` (either abstract or concrete) and any `args`, when calling `S(args...)`, if the call returns it should return a value that `isa S`. So the concrete type constructor (`MyType{T}`) is, in a sense, more basic than the abstract type constructor (`MyType`). So IMO the former option in your question is much preferable than the latter.

Furthermore, the former option may make it easier for the programmer to be easy on the compiler (regarding type inference) when necessary, although this would rarely matter.
