I'm puzzled by how Julia handles the block of code below:
a = [1,2,3]
a .= a/2 .= o = a .* 2
The output for both 'a' and 'o' is [2,4,6]. However, I don't understand why the result for 'a' is the same as if I had used a .= a*2
. Is a/2
treated as a variable and passed the array [2,4,6]
(the result of a*2
)? And then this "variable" a/2
is passed to a
? I would have expected a
to have stayed as [1,2,3]
. I'm uncertain as to whether Julia executes these operations in a specific order.
The expression a / 2
creates a new array which initially contains the values you expect ([1,2,3]
) however the contents of that array are immediately overwritten by a broadcast assignment with the contents in the right hand side array.
Let's break down the entire expression, Julia can help us:
julia> :(a .= a/2 .= o = a .* 2)
:(a .= (a / 2 .= (o = a .* 2)))
By looking at the parentheses inserted when the Expr
is printed we see the subexpressions a bit more clearly. As you can see the top expression is a .= (result of everything on RHS)
.
Let's evaluate it in the REPL:
julia> o = a .* 2
3-element Vector{Int64}:
2
4
6
julia> a / 2 .= (o = a .* 2)
3-element Vector{Float64}:
2.0
4.0
6.0
julia> a .= (a / 2 .= (o = a .* 2))
3-element Vector{Int64}:
2
4
6
As you can see the array created by a / 2
is a Float64 array and the values are therefore converted and then converted back to Int64 when put into a
.
We can make the right hand side expression even more explicit by using Meta.show_sexpr
.
julia> :(a/2 .= o = a .* 2) |> Meta.show_sexpr
(:.=, (:call, :/, :a, 2), (:(=), :o, (:call, :.*, :a, 2)))
let's add some whitespace for clarity:
(:.=,
(:call, :/, :a, 2),
(:(=),
:o,
(:call, :.*, :a, 2)))
so this expression is broadcast assigning to the value that is returned by calling the /
function on the arguments a
and 2
. The value that is assigned is what the assignment o = a * 2
returns.