Very interesting readings.

So, let’s see if I got it right this time.

From using `Meta.@lower`

I see that `ones.(2,2).*rand.(2,2)`

is basically being “translated” into

```
julia> using .Broadcast: materialize, broadcasted
julia> bc = broadcasted(*, broadcasted(ones, 2, 2), broadcasted(rand, 2, 2))
Base.Broadcast.Broadcasted(*, (Base.Broadcast.Broadcasted(ones, (2, 2)), Base.Broadcast.Broadcasted(rand, (2, 2))))
julia> materialize(bc)
2×2 Array{Float64,2}:
1.08929 0.944512
1.08929 0.944512
```

here `bc`

holds everything necessary to “unfold” the computation, which if I understand correctly is then only performed by the `materialize`

call.

Somewhat differently instead, if I call `ones(2,2).*rand(2,2)`

this translates into

```
julia> bc = broadcasted(*, ones(2,2), rand(2,2))
Base.Broadcast.Broadcasted(*, ([1.0 1.0; 1.0 1.0], [0.19239965952523885 0.8796361629139042; 0.1939935696169941 0.0831963706586214]))
julia> materialize(bc)
2×2 Array{Float64,2}:
0.1924 0.879636
0.193994 0.0831964
```

which I could also achieve by writing

```
a, b = broadcasted(ones, 2, 2), broadcasted(rand, 2, 2)
bc = broadcasted(*, materialize(a), materialize(b))
materialize(bc)
```

So, I went and checked how `materialize`

works. I’m not entirely sure I understand it but, from what I got, it `instantiate`

s the (otherwise lazy) `Broadcasted`

object.

So the difference between calling it only only on the “fused” expression and calling it in each single case is:

- doing
`@. ones(2,2)*rand(2,2)`

does not “apply” (`instantiate`

) any function/object until the very end
- doing
`broadcasted(*, ones(2,2), rand(2,2))`

instead “`instantiate`

s” the two arrays before calling the broadcast operation (though `instantiate`

is probably not the correct term here).

I think I got it. I still find it unintuitive from a “high-level” perspective, but at least I understand a bit what’s going on now (which will hopefully prevent bugs in the future).