# Inferring Parametric Types that aren't the last one

**URL:** https://discourse.julialang.org/t/inferring-parametric-types-that-arent-the-last-one/133629
**Category:** General Usage
**Tags:** question
**Created:** [November 3, 2025, 7:12pm UTC](https://discourse.julialang.org/t/inferring-parametric-types-that-arent-the-last-one/133629 "2025-11-03T19:12:45Z")
**Posts on this page:** 3
**Page:** 1

<div class="post-metadata">

### Author: ![bmit](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bmit/32/12443_2.png) [@bmit](https://discourse.julialang.org/u/bmit)
#### Post date: [November 3, 2025, 7:12pm UTC](https://discourse.julialang.org/t/inferring-parametric-types-that-arent-the-last-one/133629/1 "2025-11-03T19:12:45Z")

</div>

I apologize in advance for the basic question. I’m trying to write an outer constructor for the following MWE that infers the numeric type `T` from the arguments. The final constructor fails, because you’re only allowed to exclude trailing type parameters in Julia. What is the _right_ way to add an outer constructor for this type that infers `T` from the arguments?

```julia-auto
struct Foo{T<:Real,N,M}
    a::T
    b::NTuple{N,T}
    Foo{T,N,M}(a::T, b::NTuple{N,T}) where {T<:Real,N,M} = new{T,N,M}(a, b)
end

const Bar{T} = Foo{T,2,3}

# convert input types to T
Foo{T,N,M}(a, b::Tuple{Vararg{<:Number,N}}) where {T<:Real,N,M} = Foo{T,N,M}(T(a), T.(b))
# constant b
Foo{T,N,M}(a, b::Number) where {T<:Real,N,M} = Foo{T,N,M}(a, ntuple(i -> b, N))
# infer T (doesn't work - how to fix)
Foo{N,M}(a, b) where {N,M} = Foo{promote_type(typeof(a), eltype(b)),N,M}(a, b)

```

I’m also interested in inferring `N` if `b` is a `Tuple`.

Edit: I’ll clarify that I’m looking to be able to use both `Foo{2,3}(1.2, 3.4)` and `Bar(1.2, 3.4)`. Even if I swap the parameter order (which break other parts of my code) to `{N,M,T}`, `Bar(1.2, 3.4)` does not find a defined method.

---

<div class="post-metadata">

### Author: ![sgaure](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sgaure/32/14779_2.png) [@sgaure](https://discourse.julialang.org/u/sgaure)
#### Post date: [November 3, 2025, 8:58pm UTC](https://discourse.julialang.org/t/inferring-parametric-types-that-arent-the-last-one/133629/2 "2025-11-03T20:58:32Z")

</div>

I don’t think that is possible. I.e. `Foo{N, M}` simply means `Foo{N, M, S} where S`.

```julia-auto
julia> Foo{M,N} where {M,N} == Foo{M,N,S} where {M,N,S}
true

```

If you put the `T` last in the definition of `Foo` you can omit it.

Also, a minor point: Your first outer constructor should probably be written

```julia-auto
Foo{T,N,M}(a, b::NTuple{N,Number}) where {T<:Real,N,M} = Foo{T,N,M}(T(a), T.(b))

```

The construction you use with a `Tuple{Vararg{<:Number, N}}` is deprecated in 1.12.

```julia-auto
julia> (1, 2.0) isa Tuple{Vararg{<:Number, N}} where N
WARNING: Wrapping `Vararg` directly in UnionAll is deprecated (wrap the tuple instead).
You may need to write `f(x::Vararg{T})` rather than `f(x::Vararg{<:T})` or `f(x::Vararg{T}) where T` instead of `f(x::Vararg{T} where T)`.
To make this warning an error, and hence obtain a stack trace, use `julia --depwarn=error`.
true

```

I think it will be better to use some ordinary functions for instantiation of `Foo` objects. The outer constructor methods are quite restricted.

---

<div class="post-metadata">

### Author: ![bmit](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bmit/32/12443_2.png) [@bmit](https://discourse.julialang.org/u/bmit)
#### Post date: [November 4, 2025, 2:04am UTC](https://discourse.julialang.org/t/inferring-parametric-types-that-arent-the-last-one/133629/3 "2025-11-04T02:04:38Z")

</div>

Thank you for the feedback and advice. It took me a little while to figure out why it didn’t need to be `NTuple{N,<:Number})` - Tuple typing seems to behave differently than everything else.

Btw, this seems like the best solution I could come up with - reordering the types and adding the final outer constructor as a functor so that something like `Bar(1, 2.0)` worked.

```julia
struct Foo{N,M,T<:Real}
    a::T
    b::NTuple{N,T}
    Foo{N,M,T}(a::T, b::NTuple{N,T}) where {N,M,T<:Real} = new{N,M,T}(a, b)
end

const Bar{T} = Foo{2,3,T}

# convert input types to T
Foo{N,M,T}(a, b::NTuple{N,Number}) where {N,M,T} = Foo{N,M,T}(T(a), T.(b))
# constant b
Foo{N,M,T}(a, b::Number) where {N,M,T} = Foo{N,M,T}(a, ntuple(i -> b, N))
# infer T (how?)
(::Type{Foo{N,M,<:Any}})(a, b) where {N,M} = Foo{N,M,promote_type(typeof(a), eltype(b))}(a, b)

```

What exactly do you mean by using ordinary functions for instatiating `Foo` objects? Do you mean defining a function `foo()` and associated methods?
