# Question on semantics of loops, maps, and broadcast

**URL:** https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706
**Category:** Performance
**Created:** [November 4, 2019, 6:38pm UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706 "2019-11-04T18:38:11Z")
**Posts on this page:** 7
**Page:** 1

<div class="post-metadata">

### Author: ![klaff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klaff/32/7637_2.png) [@klaff](https://discourse.julialang.org/u/klaff)
#### Post date: [November 4, 2019, 6:38pm UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706/1 "2019-11-04T18:38:11Z")

</div>

I’ve been playing with writing things in different forms, for example the following:

```julia
function f_by_loop!(data,x)
    @inbounds for i in eachindex(data)
        data[i] = min(x,data[i])
    end
end

```

vs `data .= min.(x,data)` or `map!(y -> min(y,x), data, data)`.  
where, for example, `data=randn(100_000_000)` and `x=1.0`.

These do the same thing and once I added `@inbounds` to the loop, all three performed similarly.

The broadcast form is definitely the most concise and I’m guessing the least error prone.

My question is: Is broadcast also preferable to the manual loop because it does not unnecessarily specify an order of operation, making it easier for the compiler to optimize?

---

<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: [November 4, 2019, 7:41pm UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706/2 "2019-11-04T19:41:58Z")

</div>

In my experience, the advantages of broadcasting are:

1. Loop fusion ([More Dots: Syntactic Loop Fusion in Julia](https://julialang.org/blog/2017/01/moredots)), which can also be achieved with manual loops, just more verbosely.
2. Support for efficient operations on more esoteric containers. For example, broadcasting over a sparse array can avoid unnecessarily traversing all of the zero entries:

```julia
julia> function f_loop!(y, x)
         for i in eachindex(y)
           @inbounds y[i] = x[i]
         end
       end
f_loop! (generic function with 1 method)

julia> x = sprand(100, 100, 0.001);

julia> @btime y .= $x setup=(y = similar(x));
  37.082 ns (0 allocations: 0 bytes)

julia> @btime f_loop!(y, x) setup=(y = similar(x))
  60.394 μs (0 allocations: 0 bytes)

```

There’s an efficient way to iterate over only the nonzeros in a sparse array, but broadcasting is smart enough to do that for you.

This also enables clever packages like [https://github.com/tkoolen/TypeSortedCollections.jl](https://github.com/tkoolen/TypeSortedCollections.jl) which allows broadcasting across heterogeneous containers.

---

<div class="post-metadata">

### Author: ![non-Jedi](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/non-jedi/32/3645_2.png) [@non-Jedi](https://discourse.julialang.org/u/non-Jedi)
#### Post date: [November 4, 2019, 7:42pm UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706/3 "2019-11-04T19:42:09Z")

</div>

I’m not entirely sure what you mean by “preferable” (some options: more performant, considered better style, etc.), but with loops please do note that the `@simd` annotation can be used to indicate to the compiler that the loop iterations are independent and can be reordered.

---

<div class="post-metadata">

### Author: ![mancellin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mancellin/32/13971_2.png) [@mancellin](https://discourse.julialang.org/u/mancellin)
#### Post date: [November 4, 2019, 9:34pm UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706/4 "2019-11-04T21:34:35Z")

</div>

Note also that, even if they overlap almost exactly for functions of a single argument, they can mean different things for functions of two or more arguments.

Compare

```julia
map((x,y) -> x + y, ones(1, 4), ones(4))

```

and

```julia
broadcast((x,y) -> x + y, ones(1, 4), ones(4))

```

---

<div class="post-metadata">

### Author: ![klaff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klaff/32/7637_2.png) [@klaff](https://discourse.julialang.org/u/klaff)
#### Post date: [November 5, 2019, 2:14am UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706/5 "2019-11-05T02:14:48Z")

</div>

Good point about the dimensional magic of broadcast.

---

<div class="post-metadata">

### Author: ![klaff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klaff/32/7637_2.png) [@klaff](https://discourse.julialang.org/u/klaff)
#### Post date: [November 5, 2019, 2:18am UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706/6 "2019-11-05T02:18:52Z")

</div>

Thanks,

I figured out that the loop version was using SIMD instructions once I applied `@inbounds`. I believe `@simd` wasn’t necessary because there is no reduction aspect of the problem I chose as an example.

---

<div class="post-metadata">

### Author: ![klaff](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/klaff/32/7637_2.png) [@klaff](https://discourse.julialang.org/u/klaff)
#### Post date: [November 5, 2019, 3:10am UTC](https://discourse.julialang.org/t/question-on-semantics-of-loops-maps-and-broadcast/30706/7 "2019-11-05T03:10:00Z")

</div>

Thanks for the link - that was helpful.
