# Is broadcast! supposed to work on StaticArrays?

**URL:** https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977
**Category:** General Usage
**Created:** [March 26, 2018, 12:09am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977 "2018-03-26T00:09:33Z")
**Posts on this page:** 9
**Page:** 1

<div class="post-metadata">

### Author: ![aaowens](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaowens/32/12101_2.png) [@aaowens](https://discourse.julialang.org/u/aaowens)
#### Post date: [March 26, 2018, 12:09am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/1 "2018-03-26T00:09:33Z")

</div>

```julia
julia> sv = SVector{3}(ones(3))
3-element StaticArrays.SArray{Tuple{3},Float64,1,3}:
 1.0
 1.0
 1.0

julia> sv .= sv .+ sv
ERROR: setindex!(::StaticArrays.SArray{Tuple{3},Float64,1,3}, value, ::Int) is not defined.
Stacktrace:
 [1] setindex!(::StaticArrays.SArray{Tuple{3},Float64,1,3}, ::Float64, ::Int64) at /home/andrew/.julia/v0.6/StaticArrays/src/indexing.jl:3
 [2] macro expansion at /home/andrew/.julia/v0.6/StaticArrays/src/broadcast.jl:215 [inlined]
 [3] _broadcast!(::##3#4, ::StaticArrays.Size{(3,)}, ::StaticArrays.SArray{Tuple{3},Float64,1,3}, ::Tuple{StaticArrays.Size{(3,)}}, ::StaticArrays.SArray{Tuple{3},Float64,1,3}) at /home/andrew/.julia/v0.6/StaticArrays/src/broadcast.jl:170
 [4] broadcast!(::Function, ::StaticArrays.SArray{Tuple{3},Float64,1,3}, ::StaticArrays.SArray{Tuple{3},Float64,1,3}) at ./broadcast.jl:206

```

If this worked, `.=` would work as expected regardless of if `sv` is an Array or StaticArray.

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [March 26, 2018, 12:22am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/2 "2018-03-26T00:22:01Z")

</div>

> [@aaowens](#):
>
> If this worked, .= would work as expected regardless of if sv is an Array or StaticArray.

StaticArrays are not mutable, so this cannot work on them since `.=` lowers to `broadcast!` which mutates the values instead of returning them. Besides, SArrays shouldn’t be broadcasted anyways. You’ll notice it’s faster to let them utilize their unrolled fast arithmetic rather than using the anonymous function of broadcast. You need to code for these two cases very differently.

---

<div class="post-metadata">

### Author: ![vchuravy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/vchuravy/32/8_2.png) [@vchuravy](https://discourse.julialang.org/u/vchuravy)
#### Post date: [March 26, 2018, 12:54am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/3 "2018-03-26T00:54:50Z")

</div>

> [@ChrisRackauckas](#):
>
> Besides, SArrays shouldn’t be broadcasted anyways. You’ll notice it’s faster to let them utilize their unrolled fast arithmetic rather than using the anonymous function of broadcast. You need to code for these two cases very differently.

I disagree. There is no reason why you shouldn’t use `broadcast` and `SArrays`. The unrolled cases come into play for linear algebra operations, but there is no relation with elementwise operations . If broadcast is indeed slow for `SArrays` we need to fix it (and there is no apriori reason why it shouldn’t be fast, since you could unroll the entire broadcast operation).

The question whether or not `.=` should work for `SArrays` is debatable. Since the SArray is immutable asking for it to be overwritten makes little sense, but I would be in favour of making `.=` mean `=` for `SArrays` (and other immutable containers). Being able to use broadcast in generic code is important.

Right now the lowering of `.=` prevents `SArray` from defining that.

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [March 26, 2018, 1:01am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/4 "2018-03-26T01:01:53Z")

</div>

> [@vchuravy](#):
>
> I disagree. There is no reason why you shouldn’t use broadcast and SArrays. The unrolled cases come into play for linear algebra operations, but there is no relation with elementwise operations . If broadcast is indeed slow for SArrays we need to fix it (and there is no apriori reason why it shouldn’t be fast, since you could unroll the entire broadcast operation).

Sure, there’s no a priori reason why it shouldn’t be fast, but right now it isn’t so it should be avoided. If that gets changed then that would help a lot. I wasn’t talking about a hypothetical future, I was talking about writing code right now (this has a `Usage` tag and not a `Development` tag. I agree that the noted issues maybe could be solved in the future, but I don’t see a reason to believe it will change soon at all).

---

<div class="post-metadata">

### Author: ![aaowens](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aaowens/32/12101_2.png) [@aaowens](https://discourse.julialang.org/u/aaowens)
#### Post date: [March 26, 2018, 1:08am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/5 "2018-03-26T01:08:13Z")

</div>

Ok. This came up because I was trying to use `LineSearches.jl` with an `SVector`. It’s typed for `AbstractArray` but fails at a `.=` line.

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [March 26, 2018, 1:48am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/6 "2018-03-26T01:48:36Z")

</div>

> [@ChrisRackauckas](#):
>
> SArrays shouldn’t be broadcasted anyways. You’ll notice it’s faster to let them utilize their unrolled fast arithmetic rather than using the anonymous function of broadcast.

StaticArrays’s `broadcast` and `broadcast!` are fully unrolled (as in, the generated function creates an expression for each element of the destination without any runtime for-loops). `+`, `-`, etc. are all defined in terms of `broadcast` and `map`, e.g.

```julia
@inline +(a::Number, b::StaticArray) = broadcast(+, a, b)

```

`broadcast!` to `MArray` is also specialized, and with [Fix #385, broadcast! with non-static LHS broken on Julia master by tkoolen · Pull Request #387 · JuliaArrays/StaticArrays.jl · GitHub](https://github.com/JuliaArrays/StaticArrays.jl/pull/387), `broadcast!`ing statically sized arguments to an `Array` will also use that machinery instead of the generic `broadcast!` in Base.

---

<div class="post-metadata">

### Author: ![ChrisRackauckas](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/chrisrackauckas/32/77_2.png) [@ChrisRackauckas](https://discourse.julialang.org/u/ChrisRackauckas)
#### Post date: [March 26, 2018, 2:00am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/7 "2018-03-26T02:00:05Z")

</div>

> [@tkoolen](#):
>
> StaticArrays’s broadcast and broadcast! are fully unrolled (as in, the generated function creates an expression for each element of the destination without any runtime for-loops). +, -, etc. are all defined in terms of broadcast and map, e.g.

That’s not what shows up empirically. I remember we did a big change because of it: [Don't broadcast out-of-place · Issue #235 · SciML/OrdinaryDiffEq.jl · GitHub](https://github.com/JuliaDiffEq/OrdinaryDiffEq.jl/issues/235). Though there may have been something other Base broadcasting bug involved like [Performance issues with fusing 12+ broadcasts · Issue #22255 · JuliaLang/julia · GitHub](https://github.com/JuliaLang/julia/issues/22255). Just a quick example:

```julia
function f(x,y,z)
    x .+ y .+ z
end
function g(x,y,z)
    x + y + z
end
using StaticArrays, BenchmarkTools
x = @SVector [2.0,3.0,4.0]
y = @SVector [2.0,3.0,4.0]
z = @SVector [2.0,3.0,4.0]

@btime f(x,y,z) # 33.372 μs (21 allocations: 768 bytes)
@btime g(x,y,z) # 19.085 ns (1 allocation: 32 bytes)

@btime f($x,$y,$z) # 3.220 ns (0 allocations: 0 bytes)
@btime g($x,$y,$z) # 3.220 ns (0 allocations: 0 bytes)

```

So I don’t know, but removing broadcast was a big improvement in the larger package for some reason 🤷‍♂️. (But we can discuss this more in a separate thread)

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [March 26, 2018, 2:21am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/8 "2018-03-26T02:21:03Z")

</div>

> [@vchuravy](#):
>
> I would be in favour of making .= mean = for SArrays (and other immutable containers). Being able to use broadcast in generic code is important.

Not sure if I’m a fan of that. I think it could be pretty confusing. Also, to support both mutable and non-mutable arrays, you’d have to do something like

```julia
function f(x::AbstractArray)
    y = similar(x) # needed for Array, what should `similar` do for StaticArray?
    y .= x.^2
    y
end

```

`similar(::StaticArray)` could just call `zeros`, but I’d be worried that the compiler wouldn’t be able to optimize this away, especially if the `broadcast!`ed function is not inlined. So you’re going to have suboptimal performance for `StaticArray`s, and I think quite a few `StaticArrays` users want to squeeze every bit of performance out of the algorithm.

More or less related: [Fix #385, broadcast! with non-static LHS broken on Julia master by tkoolen · Pull Request #387 · JuliaArrays/StaticArrays.jl · GitHub](https://github.com/JuliaArrays/StaticArrays.jl/pull/387).

---

<div class="post-metadata">

### Author: ![tkoolen](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkoolen/32/1603_2.png) [@tkoolen](https://discourse.julialang.org/u/tkoolen)
#### Post date: [March 26, 2018, 2:43am UTC](https://discourse.julialang.org/t/is-broadcast-supposed-to-work-on-staticarrays/9977/9 "2018-03-26T02:43:10Z")

</div>

The results for non-interpolated `x`, `y`, and `z` can probably be explained by having to perform runtime dispatch for every element (with `f`) vs. only once (with `g`). So I can see how it can make a sizeable difference in type-unstable code.

If `x`, `y`, and `z` ~~all have the same dimensions~~ are all `StaticArray`s, `+` will actually call `map` (which is also specialized and fully unrolled in `StaticArrays`). So another difference could be that there’s no “loop fusion” (quotes because there is no actual loop) with `x + y + z`, while `x .+ y .+ z` is fused. Maybe that results in operations being performed in a different order, which could have some influence. Some of those differences might go away as the compiler performs optimization, but I guess there could be differences.

Edit: also, the fact that several unfused `map`s are called vs. one fused `broadcast` could certainly have been a big difference in light of inference limits, as in your [https://github.com/JuliaLang/julia/issues/22255](https://github.com/JuliaLang/julia/issues/22255).
