# Understanding the behaviour of @. macro

**URL:** <https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680>\
**Category:** New to Julia\
**Created:** [May 24, 2024, 2:26pm UTC](https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680 "2024-05-24T14:26:14Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![Janik](https://avatars.discourse-cdn.com/v4/letter/j/f475e1/32.png) [@Janik](https://discourse.julialang.org/u/Janik)\
**Post date:** [May 24, 2024, 2:26pm UTC](https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680/1 "2024-05-24T14:26:14Z")

</div>

Hi,

I am very new to Julia and was playing around with `@.` (using Julia 1.10.3) and noticed that I can compute the expression

```julia
5 .* rand(10) .+ 2

```

as expected, however when I use

```julia
@. 5*rand(10) + 2

```

it does not work and gives the error “MethodError: no method matching +(::Vector{Float64}, ::Int64)”.

```julia
@macroexpand @. 5*rand(10) + 2
:((+).((*).(5, rand.(10)), 2))

```

Using `@macroexpand` I realised the error seems to be in the difference of `rand.(10)` and `rand(10)` as

```julia
(+).(rand(10), 2) # works
(+).(rand.(10), 2) # does not work, MethodError: no method matching +(::Vector{Float64}, ::Int64)

```

which seems weird to me, as `rand(10)` produces a Vector of floats, but so does `rand.(10)`, hence there seems to be a method available to add a float vector and an integer.

What am I missing here?  
Thank you very much in advance!

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [May 24, 2024, 2:44pm UTC](https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680/2 "2024-05-24T14:44:31Z")

</div>

Yeah, this is a very confusing one, verging on cursed. One way to think of it is that broadcast is creating a simple loop over all the dotted expressions, so you can think of `rand.(xs) .+ ys` as something kinda like `[rand(x) + y for x in xs, y in ys]`. But that won’t work because `rand(10)` gives you a vector and you can’t add (_without_ broadcasting, but remember we _already_ did the broadcast transform) a scalar to a vector.

There are a few things that make this especially confusing:

- `5 .* rand.(10)` works, because you _can_ multiply a scalar by a vector.
- `rand.(10)` — _by itself_ — is functionally equivalent to `rand(10)` because, at the _end_ of a broadcast expression, Julia “unwraps” zero-dimensional results. Theoretically, the “correct” answer to `rand.(10)` would be a zero-dimensional array that contains a 10-element vector, but that’s quite cumbersome in many situations. See julia#28866 for more on this.

The simplest guideline is that broadcasting works most seamlessly for functions functions that take scalars and return a single value. To avoid `@.` from affecting functions like `rand` (or `ones` or `zeros` or any of the like), you can “protect” them with a `$`. That is, `@. 5 * $rand(10) + 2`.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [May 24, 2024, 4:57pm UTC](https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680/3 "2024-05-24T16:57:40Z")

</div>

Note also that if you have something else to provide the shape of the array, then you can just use `rand.()`.

For example, with a pre-allocated output `x = zeros(10)`, you can do:

```julia
@. x = 5 * rand() + 2

```

and it will expand out to a separate call to `rand()` for each element, without ever allocating an array of random numbers. Another example would be where you are combining random number with some other array, e.g.

```julia
@. 5 * rand() + (1:10)

```

---

<div class="post-metadata">

**Author:** ![miguelraz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/miguelraz/32/631_2.png) [@miguelraz](https://discourse.julialang.org/u/miguelraz)\
**Post date:** [May 24, 2024, 8:54pm UTC](https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680/4 "2024-05-24T20:54:49Z")

</div>

into the blog it goes

---

<div class="post-metadata">

**Author:** ![Janik](https://avatars.discourse-cdn.com/v4/letter/j/f475e1/32.png) [@Janik](https://discourse.julialang.org/u/Janik)\
**Post date:** [May 25, 2024, 12:25am UTC](https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680/5 "2024-05-25T00:25:46Z")

</div>

Thank you very much for the insightful answer!

Using another example, I don’t understand why this fails

```julia
5 .* zeros.() .+ 2
# MethodError: no method matching +(::Array{Float64, 0}, ::Int64) 
# For element-wise addition, use broadcasting with dot syntax: array .+ scalar

```

but this works

```julia
x = 5 .* zeros.()
x .+ 2
# 2.0

```

I guess x provided the shape for the broadcasting as in @stevengj answer, but what is the intention of the behaviour of the first example? Even the error message is basically saying I did it correct 😅

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [May 25, 2024, 12:47am UTC](https://discourse.julialang.org/t/understanding-the-behaviour-of-macro/114680/6 "2024-05-25T00:47:49Z")

</div>

> [@Janik](#):
>
> Using another example, I don’t understand why this fails
> 
> ```julia
> 5 .* zeros.() .+ 2
> # MethodError: no method matching +(::Array{Float64, 0}, ::Int64) 
> 
> ```

Think of assigning this to an array — the broadcast means that _each element_ will be computed as `5 * zeros() + 2`, but this fails because `zeros()` returns a 0-dimensional array, and `5 * zeros()` (`scalar * array` = `array`) is a 0-dimensional array, but Julia doesn’t define a method for `array + scalar` for _any_ dimensionality of array:

```julia
julia> zeros()
0-dimensional Array{Float64, 0}:
0.0

julia> zeros() + 1
ERROR: MethodError: no method matching +(::Array{Float64, 0}, ::Int64)

```

In contrast, it works with `rand.()` because `rand()` returns a scalar.
