Broadcasting behavior of @. with functions?

I have a question regarding the use of the @. macro as it does not work when used to broadcast the result of an anonymous function.

Here is an example below which works.

x = 1.
z = [1., 1.]
@. (z - x)

Now I replace z with an anonymous function:

x = 1.
z = (n) -> repeat([1.], n)
@. (z(2) - x) 

and I get the error:

MethodError: no method matching -(::Vector{Float64}, ::Float64)
For element-wise subtraction, use broadcasting with dot syntax: array .- scalar

Using .- indeed works.

x = 1.
z = (n) -> repeat([1.], n)
(z(2) .- x) 

I don’t understand though as I expect @. (z(x) - x) expands to z.(2) .- x.

julia> using MacroTools
julia> MacroTools.@expand @. (z(2) - x) 
:((-).(z.(2), x))

The only difference is z.(2) which is equal to z(2) in this case.

julia> isequal(z(2), z.(2))
true

So… why does the @. macro not work?

Edit. I guess it is the same reason why z.(2) .- x does not work while z(2) .- x does, even though z.(2) and z(2) are the same, which I still don’t understand.

this is correct. note that you can opt-out expressions from inside @. via $ like so

julia> @. ($z(2) - x)
2-element Vector{Float64}:
 0.0
 0.0

z.(2) and z(2) are the same, which I still don’t understand.

this is simply because integers are iterable, unfortunately

julia> collect(i for i in 2)
0-dimensional Array{Int64, 0}:
2

edit:
eesh there is indeed some extra confusing thing going on with dot fusion

1 Like

I think this is the inverse of broadcast should not drop zero-dimensional results to scalars · Issue #28866 · JuliaLang/julia · GitHub, which is interesting. In short z(2) and z.(2) are only the same at the end of a broadcast expression because Julia removes the 0-d container at the end but not in the middle.

1 Like

Ok I think I got it.

z.(2) .- x is equivalent to [z(i) - x for i in 2].

z(2) .- x is equivalent to [i - x for i in z(2)].

Thanks for the $. I was trying Ref on 2 like z.(Ref(2)) (scalar still being iterable) and Ref(z.(2)) (argument not a scalar) but I see now why they don’t work.

Thanks. This link from that other thread was kind of helpful and more confusing at the same time.