# Type stability issues when broadcasting

**URL:** <https://discourse.julialang.org/t/type-stability-issues-when-broadcasting/92715>\
**Category:** Performance\
**Tags:** struct, type-stability, functions, views\
**Created:** [January 9, 2023, 2:24pm UTC](https://discourse.julialang.org/t/type-stability-issues-when-broadcasting/92715 "2023-01-09T14:24:30Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![jpdoane](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jpdoane](https://discourse.julialang.org/u/jpdoane)\
**Post date:** [January 9, 2023, 2:24pm UTC](https://discourse.julialang.org/t/type-stability-issues-when-broadcasting/92715/1 "2023-01-09T14:24:30Z")

</div>

I am seeing some odd type instability issues when broadcasting.

Simple functions seem to become type-unstable when broadcasting over multiple views:

```julia
f1(x::AbstractVector{T}) where T = 1
f2(x::AbstractVector{T}) where T = x .+ 1

#@code_warntype f1(rand(2)) # Type Stable
#@code_warntype f1.(eachcol(rand(2,2))) # Type Stable
#@code_warntype f2(rand(2)) # Type Stable
@code_warntype f2.(eachcol(rand(2,2))) # Not Type Stable

```

Output:

```julia
MethodInstance for (::var"##dotfunction#358#54")(::Base.Generator{Base.OneTo{Int64}, Base.var"#242#243"{Matrix{Float64}}})
  from (::var"##dotfunction#358#54")(x1) in Main
Arguments
  #self#::Core.Const(var"##dotfunction#358#54"())
  x1::Base.Generator{Base.OneTo{Int64}, Base.var"#242#243"{Matrix{Float64}}}
Body::Any
1 ─ %1 = Base.broadcasted(Main.f2, x1)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(f2), Tuple{Vector{SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}}}}
│ %2 = Base.materialize(%1)::Any
└── return %2

```

Broadcasting also appears to be type-unstable for any function that is called as member of a struct, even when the struct is parametrically typed to the function

```julia
struct MyStruct{F<:Function}
    f::F
end

f3(x) = 1
s3 = MyStruct(f3)

#@code_warntype s3.f(1) # Type Stable
@code_warntype s3.f.([1,2,3]) # Not type Stable

```

Output

```julia
MethodInstance for (::var"##dotfunction#357#53")(::Vector{Int64})
  from (::var"##dotfunction#357#53")(x1) in Main
Arguments
  #self#::Core.Const(var"##dotfunction#357#53"())
  x1::Vector{Int64}
Body::Any
1 ─ %1 = Base.getproperty(Main.s, :f)::Any
│ %2 = Base.broadcasted(%1, x1)::Any
│ %3 = Base.materialize(%2)::Any
└── return %3

```

Not sure if these two examples are related or reflect separate issues.

---

<div class="post-metadata">

**Author:** ![skleinbo](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/skleinbo/32/36080_2.png) [@skleinbo](https://discourse.julialang.org/u/skleinbo)\
**Post date:** [January 9, 2023, 5:56pm UTC](https://discourse.julialang.org/t/type-stability-issues-when-broadcasting/92715/2 "2023-01-09T17:56:17Z")

</div>

Hilariously, the type is properly inferred when you do

```julia
julia> f3(x::AbstractArray{T,N}) where {T,N} = x .+ 1
f3 (generic function with 1 method)

julia> @code_warntype f3.(eachcol(rand(2,2)))
MethodInstance for (::var"##dotfunction#341#7")(::Base.Generator{Base.OneTo{Int64}, Base.var"#242#243"{Matrix{Float64}}})
  from (::var"##dotfunction#341#7")(x1) in Main
Arguments
  #self#::Core.Const(var"##dotfunction#341#7"())
  x1::Base.Generator{Base.OneTo{Int64}, Base.var"#242#243"{Matrix{Float64}}}
Body::Vector{Vector{Float64}}
1 ─ %1 = Base.broadcasted(Main.f3, x1)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(f3), Tuple{Vector{SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}}}}
│ %2 = Base.materialize(%1)::Vector{Vector{Float64}}
└── return %2

```

I’m sure there is a very good reason I too would love to understand.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [January 9, 2023, 6:49pm UTC](https://discourse.julialang.org/t/type-stability-issues-when-broadcasting/92715/3 "2023-01-09T18:49:52Z")

</div>

The second example is resolved when nested within another function

```julia-repl
julia> fs3(s3) = s3.f.([1,2,3])
fs3 (generic function with 1 method)
julia> @code_warntype fs3(s3)
  # stable

```

so is likely an artifact. Note that `code_warntype` is not entirely trustworthy. It takes a rather naive view of how things work and often neglects certain exceptions that occur in practice (I recall [Be-aware-of-when-Julia-avoids-specializing](https://docs.julialang.org/en/v1/manual/performance-tips/#Be-aware-of-when-Julia-avoids-specializing) being one such example). Nesting within functions _sometimes_ helps.

The first example is not resolved, however:

```julia-repl
julia> ff2(x) = f2.(eachcol(x))
ff2 (generic function with 1 method)

julia> @code_warntype ff2(rand(2,2))
  # still unstable

```

Someone else will have to elaborate on this case. I don’t fully understand it.

---

<div class="post-metadata">

**Author:** ![wsshin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/wsshin/32/360_2.png) [@wsshin](https://discourse.julialang.org/u/wsshin)\
**Post date:** [February 9, 2023, 6:31pm UTC](https://discourse.julialang.org/t/type-stability-issues-when-broadcasting/92715/4 "2023-02-09T18:31:18Z")

</div>

I thought `f2.(x)` is equivalent to `Base.materialize(Base.broadcasted(f2, x))`:

```julia-repl
julia> @code_lowered f2.(eachcol(rand(2,2)))
CodeInfo(
1 ─ %1 = Base.broadcasted(Main.f2, x1)
│ %2 = Base.materialize(%1)
└── return %2
)

```

Strangely, the direct execution of this seemingly equivalent code is type-stable:

```julia-repl
julia> @code_warntype Base.materialize(Base.broadcasted(f2, eachcol(rand(2,2))))
MethodInstance for Base.Broadcast.materialize(::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(f2), Tuple{ColumnSlices{Matrix{Float64}, Tuple{Base.OneTo{Int64}}, SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}}}})
  from materialize(bc::Base.Broadcast.Broadcasted) @ Base.Broadcast broadcast.jl:873
Arguments
  #self#::Core.Const(Base.Broadcast.materialize)
  bc::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Nothing, typeof(f2), Tuple{ColumnSlices{Matrix{Float64}, Tuple{Base.OneTo{Int64}}, SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}}}}
Body::Vector{Vector{Float64}}
1 ─ nothing
│ %2 = Base.Broadcast.instantiate(bc)::Base.Broadcast.Broadcasted{Base.Broadcast.DefaultArrayStyle{1}, Tuple{Base.OneTo{Int64}}, typeof(f2), Tuple{ColumnSlices{Matrix{Float64}, Tuple{Base.OneTo{Int64}}, SubArray{Float64, 1, Matrix{Float64}, Tuple{Base.Slice{Base.OneTo{Int64}}, Int64}, true}}}}
│ %3 = Base.Broadcast.copy(%2)::Vector{Vector{Float64}}
└── return %3

```

---

<div class="post-metadata">

**Author:** ![uniment](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/uniment/32/24532_2.png) [@uniment](https://discourse.julialang.org/u/uniment)\
**Post date:** [February 12, 2023, 8:39am UTC](https://discourse.julialang.org/t/type-stability-issues-when-broadcasting/92715/5 "2023-02-12T08:39:09Z")

</div>

> [@mikmoore](#):
>
> The first example is not resolved, however:

It is if you try this:

```julia
julia> ff2(x) = f2.(eachcol(x))
ff2 (generic function with 1 method)

julia> ff2(rand(2,2)); # run it at least once

julia> @code_warntype ff2(rand(2,2))
  # stable

```

> [@](#):
>
> I don’t fully understand it

same.
