# Method matching an array with elements of a composite type with parametric types

**URL:** <https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271>\
**Category:** General Usage\
**Tags:** parametric-types, parametric-methods\
**Created:** [March 1, 2021, 5:58pm UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271 "2021-03-01T17:58:54Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![mroavi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mroavi/32/8804_2.png) [@mroavi](https://discourse.julialang.org/u/mroavi)\
**Post date:** [March 1, 2021, 5:58pm UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/1 "2021-03-01T17:58:54Z")

</div>

Here is my composite type:

```julia
mutable struct Factor{T, N}
  vars::NTuple{N,Int64}
  vals::Array{T,N}
end

```

How can I define a method that matches arrays with elements of this type and that can access the parametric type `T`?

Here is my attempt:

```julia
function product(F::Array{Factor{T,N},1}) where {T,N}
  reduce(product, F; init = Factor{T}((), Array{T,0}(undef)))
end

```

But it fails:

```julia
A = Factor{Float64,1}((1,), [0.11; 0.89])
B = Factor{Float64,2}((2, 1), [0.59 0.22; 0.41 0.78])
C = product([A, B])

```

Error:

```julia
MethodError: no method matching product(::Array{Factor{Float64,N} where N,1})

```

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [March 1, 2021, 6:11pm UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/2 "2021-03-01T18:11:22Z")

</div>

The signature `product(F::Array{Factor{T,N},1}) where {T,N}` requires that `N` be a defined value for the whole (specialized) method. But in your case you want to allow different `N` values for different array elements, so you can write:

```julia
function product(F::Array{Factor{T,N} where N, 1}) where T
  # ... code that uses `T`
end

```

or equivalently, just leave `N` unspecified:

```julia
function product(F::Array{Factor{T}, 1}) where T
  # ... code that uses `T`
end

```

However, you need to change the body of the method to choose a specific `N` when you instantiate a `Factor`.

---

<div class="post-metadata">

**Author:** ![mroavi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mroavi/32/8804_2.png) [@mroavi](https://discourse.julialang.org/u/mroavi)\
**Post date:** [March 1, 2021, 6:27pm UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/3 "2021-03-01T18:27:26Z")

</div>

Thank you very much (also for anticipating the next bug in my program)

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [March 1, 2021, 6:47pm UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/4 "2021-03-01T18:47:11Z")

</div>

> [@sijo](#):
>
> `product(F::Array{Factor{T}, 1}) where T`

This will _only_ work when the user has specifically created an `Array{Factor{T}, 1}`, that is, an array in which every different element can have a potentially different `N` in its `Factor` parameters. That’s almost certainly not what you want, because it will fail in some simple cases:

```julia
julia> product([A])
ERROR: MethodError: no method matching product(::Array{Factor{Float64,1},1})
You may have intended to import Base.product
Closest candidates are:
  product(::Array{Factor{T,N} where N,1}) where T at REPL[4]:1
Stacktrace:
 [1] top-level scope at REPL[5]:100: 

```

You almost certainly want:

```julia
function product(F::Array{<:Factor{T}, 1}) where {T}
  # code that uses `T`
end

```

which accepts _any_ array whose element type is some subtype of `Factor{T}`.

Even better, unless you actually care about only accepting the built-in type `Array` and not any other array-like object, you probably want:

```julia
function product(F::AbstractArray{<:Factor{T}, 1}) where {T}

```

or, exactly equivalently:

```julia
function product(F::AbstractVector{<:Factor{T}}) where {T}

```

since `AbstractVector{T}` is exactly `AbstractArray{T, 1}`.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [March 1, 2021, 6:54pm UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/5 "2021-03-01T18:54:37Z")

</div>

Or maybe even

```julia
function product(F::AbstractArray{<:Factor{T}}) where {T}

```

?

---

<div class="post-metadata">

**Author:** ![mroavi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mroavi/32/8804_2.png) [@mroavi](https://discourse.julialang.org/u/mroavi)\
**Post date:** [March 1, 2021, 11:52pm UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/6 "2021-03-01T23:52:15Z")

</div>

Could you explain why

```julia
product(F::Array{Factor{T}, 1}) where T

```

fails in simple cases like the one you show?

You mention that:

> This will _only_ work when the user has specifically created an `Array{Factor{T}, 1}` , that is, an array in which every different element can have a potentially different `N` in its `Factor` parameters.

Isn’t

```julia
julia> product([A])

```

Covered by that statement?

In which other simple cases does it fail?

---

<div class="post-metadata">

**Author:** ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)\
**Post date:** [March 2, 2021, 6:08am UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/7 "2021-03-02T06:08:12Z")

</div>

Check out [What's with the invariant parametric types gotcha? - #3 by rdeits](https://discourse.julialang.org/t/whats-with-the-invariant-parametric-types-gotcha/55090/3) or [Why? isa([(x,1),(y,1)], Array{Tuple{Stuff,Number},1}) = false - #5 by Shuhua](https://discourse.julialang.org/t/why-isa-x-1-y-1-array-tuple-stuff-number-1-false/55777/5) or [Struggling with signatures - #2 by Henrique\_Becker](https://discourse.julialang.org/t/struggling-with-signatures/52935/2)

In particular, `Array{Factor{T}, 1}` and `Array{Factor{T, 1}, 1}` are totally different types, but they are both subtypes of `Array{<:Factor{T}, 1}`

---

<div class="post-metadata">

**Author:** ![mroavi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mroavi/32/8804_2.png) [@mroavi](https://discourse.julialang.org/u/mroavi)\
**Post date:** [March 4, 2021, 8:59am UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/8 "2021-03-04T08:59:27Z")

</div>

What change would I need to make to

```julia
function product(F::Array{Factor{T,N} where N, 1}) where T
  # ... code that uses `T`
end

```

to be able to access `N` inside the body of the function?

---

<div class="post-metadata">

**Author:** ![sijo](https://avatars.discourse-cdn.com/v4/letter/s/da6949/32.png) [@sijo](https://discourse.julialang.org/u/sijo)\
**Post date:** [March 4, 2021, 9:32am UTC](https://discourse.julialang.org/t/method-matching-an-array-with-elements-of-a-composite-type-with-parametric-types/56271/9 "2021-03-04T09:32:29Z")

</div>

You can’t… That would require that `N` is a defined value for the whole method, which is not the case.

Say the method is called like this:

```julia
A = Factor{Float64,1}((1,), [0.11; 0.89])
B = Factor{Float64,2}((2, 1), [0.59 0.22; 0.41 0.78])
C = product([A, B])

```

Here `N=1` for `A`, and `N=2` for `B`. So what should `N` be in the body of `product`?
