# Promote parametric type in repeat

**URL:** <https://discourse.julialang.org/t/promote-parametric-type-in-repeat/19323>\
**Category:** General Usage\
**Created:** [January 6, 2019, 12:48pm UTC](https://discourse.julialang.org/t/promote-parametric-type-in-repeat/19323 "2019-01-06T12:48:13Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [January 6, 2019, 12:48pm UTC](https://discourse.julialang.org/t/promote-parametric-type-in-repeat/19323/1 "2019-01-06T12:48:13Z")

</div>

Just for laziness I would like to implement a `repeat` function for my own parametric type. For example, consider the following example, where `A1` might even be used recursively (i.e. Arrays of Arrays) and I would like to do a simple repeat (introducing one further dimension, here a second one)

```julia
import Base: size, repeat
abstract type A end

struct A1{C<:Array{<:A,N} where N} <: A
    value::C
end
struct A2{T} <: A
    value::T
end

size(a::A1) = size(a.value)
repeat(a::A1; inner=nothing, outer=nothing) = A1( repeat(a.value; inner=inner, outer=outer) )
repeat(a::A1, counts...) = A1( repeat(a.value, counts...) )

function runExample()
  a = A1([A2(0.2); A2(0.2)])
  s = length(size(a))
  d = fill(1,s+1)
  d[s+1] = s
  return repeat(a; inner=d)
end
@code_warntype runExample()
runExample()

```

While the example runs perfectly (last line) the `@code_warntype` says that it can’t infer the type of the repeat return, i.e.

```julia
   11 ─ %25 = invoke Main.:(#repeat#8)(%7::Array{Int64,1}, %10::Nothing, %9::Function, %4::A1{Array{A2{Float64},1}})::A1{_1} where _1 

```

I started trying something like

```julia
repeat(a::A1{Ca}; inner=nothing, outer=nothing) where {Ca <: Array{C,N} where {C <: A, N}} = ...

```

however the new type will have a different `N`, since the array dimensions change, so I don’t know how to continue. Actually the problem is similar for `cat`, `vcat` and `hcat`.

How can I properly define `repeat` to not avoid the type instability?

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [January 7, 2019, 8:38am UTC](https://discourse.julialang.org/t/promote-parametric-type-in-repeat/19323/2 "2019-01-07T08:38:37Z")

</div>

I just noticed that it is enough to specify one of the parameters, i.e.

```julia
repeat(a::A1{C}; inner=nothing, outer=nothing) where {C <:Array{P,N}} where {P<:A,N} = A1{Array{P}}( repeat(a.value; inner=inner, outer=outer) )
repeat(a::A1{C}, counts...) where {C <:Array{P,N}} where {P<:A,N} = A1{Array{P}}( repeat(a.value, counts...) )

```

note that for the resulting type `A1{Array{P}}` the `N` is not specified. This resolves the `@code_warntype` problem partly, but there still seems to be a problem determining the resulting number dimensions.

---

<div class="post-metadata">

**Author:** ![kellertuer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kellertuer/32/220707_2.png) [@kellertuer](https://discourse.julialang.org/u/kellertuer)\
**Post date:** [January 9, 2019, 12:54pm UTC](https://discourse.julialang.org/t/promote-parametric-type-in-repeat/19323/3 "2019-01-09T12:54:52Z")

</div>

Interestingly, at least when I try to compute the dimensions of the resulting array (the lazy way), i.e. the script looks like

```julia
import Base: size, repeat
abstract type A end

struct A1{C<:Array{<:A,N} where N} <: A
    value::C
end
struct A2{T} <: A
    value::T
end

size(a::A1) = size(a.value)
function repeat(a::A1{Array{P,N}}; inner=nothing, outer=nothing) where {P<:A,N}
    b = repeat(a.value; inner=inner, outer=outer)
    return A1{Array{P,ndims(b)}}(b)
end
function repeat(a::A1{Array{P,N}}, counts...) where {P<:A,N}
    b = repeat(a.value, counts...)
    return A1(b)
end

```

Then comparing defining a function with the code running in REPL like

```julia
function runExample()
  a = A1([A2(0.2); A2(0.2)])
  s = length(size(a))
  d = fill(1,s+1)
  d[s+1] = s
  return repeat(a, d...)
end
@code_warntype runExample()
runExample()

```

vs.

```julia
a = A1([A2(0.2); A2(0.2)])
s = length(size(a))
d = fill(1,s+1)
d[s+1] = s
@code_warntype repeat(a, d...)

```

yields that the function can not infer its return type, i.e. I get (just the last part of code\_warntype)

```julia
   │ %7 = invoke Base.fill!(%6::Array{Int64,1}, 1::Int64)::Array{Int64,1} ││┃ fill
25 │ (Base.arrayset)(true, %7, 1, 2) │╻ setindex!
26 │ %9 = (Core.tuple)(%4)::Tuple{A1{Array{A2{Float64},1}}} │
   │ %10 = (Core._apply)(Main.repeat, %9, %7)::A1{_1} where _1 │
   └── return %10  

```

versus the last lines from the second code\_warntype yield

```julia
   │ %4 = invoke Main.repeat(%1::Array{A2{Float64},1}, %2::Int64, %3::Int64)::Array{A2{Float64},2} │
19 │ %5 = %new(A1{Array{A2{Float64},2}}, %4)::A1{Array{A2{Float64},2}} │╻╷ Type
   └── return %5   

```

So, interestingly, the first does know the types of `%7` and `%9` but does not use them in the `apply`, while in REPL in `invoke`s the repeat and can pass down the types. Can somebody explain (and maybe solve) this difference?
