Run the following example:
x = zeros(2)
y = zeros(3)
[x;y] .= [1.2, 4.5, 2.3, 4.5, 5.6]
Surprisingly (for me at least), x,y
are still zero after this. Why?
I am using v0.5.0.
Run the following example:
x = zeros(2)
y = zeros(3)
[x;y] .= [1.2, 4.5, 2.3, 4.5, 5.6]
Surprisingly (for me at least), x,y
are still zero after this. Why?
I am using v0.5.0.
[x;y
] constructs a new array that copies the content of x
and y
but has no connection to x
and y
after being constructed. You are assigning to that new array, not the original x
and y
.
Often the best way to examine these sorts of issues is by asking Julia itself. The expand
function removes any “syntactic sugar” and displays the code that Julia ends up running. In this case:
julia> expand(:([x;y] .= [1.2, 4.5, 2.3, 4.5, 5.6]))
:((Base.broadcast!)(Base.identity,vcat(x,y),(Base.vect)(1.2,4.5,2.3,4.5,5.6)))
That is, it’s broadcasting the identity
function over your array, and then storing the answer into the result of vcat(x,y)
. It’s the result of that vcat
operation that gets mutated… but you don’t have a reference to it, so you never see it happen.
I feel like we may want to syntactically disallow this, unless anybody can think of a useful purpose for this syntax.
It’s hard for the parser to know which functions return a view and which create a new object.
I have recently used view(...) .= ...
and the result was fast to execute, while being expressive and easy to read.
@andyferris But view([x;y]) .= [1.2, 4.5, 2.3, 5.6, 2.3]
still doesn’t work (it gives an error).
Maybe one could conceive a generalization of view
. Currently, view
only works to return a subarray, where it transparently maps indexes on the view to indices on the original array. It could be just as useful to have a function to map indexes to a super array, like a block matrix. For example, suppose I want to work with the block matrix:
M = [A11 A12; A21 A22]
without having to instantiate it (maybe the A
’s are too large). I would like a transparent way of refering to the index M[i,j]
, where it automatically maps this index to the appropriate index in the appropriate A
.
See CatViews.jl.
@ChrisRackauckas Nice!
using CatViews
x = zeros(2)
y = zeros(3)
CatView(x,y) .= [1.2, 4.5, 2.3, 4.5, 5.6]
works:
julia> [x;y]
5-element Array{Float64,1}:
1.2
4.5
2.3
4.5
5.6
No, I meant use view
instead of getindex
.
E.g. using the @view
macro,
@view(a[:, :, 3]) .+= myvector
Nice, @ChrisRackauckas
The only useful meaning I could see this having writing data in place to the two arrays, which would actually be pretty cool, but I’m not sure how reasonably we can add that functionality to Base Julia (it can be done via CatViews as demonstrated). It might make sense to disallow the syntax until it can be supported and then re-allow it.
Note that this is a bug; see e.g. https://github.com/JuliaLang/julia/issues/20623.
@mbauman: is there an equivalent to expand
in Julia v1?
Yes, it’s now called Meta.@lower
and you no longer need to worry about quoting. The internal machinations of broadcast have changed, too, but the end result in this context is the same.
julia> Meta.@lower [x;y] .= [1.2, 4.5, 2.3, 4.5, 5.6]
:($(Expr(:thunk, CodeInfo(
1 ─ %1 = (Base.vcat)(x, y)
│ %2 = (Base.vect)(1.2, 4.5, 2.3, 4.5, 5.6)
│ %3 = (Base.broadcasted)(Base.identity, %2)
│ %4 = (Base.materialize!)(%1, %3)
└── return %4
))))
I am still a bit confused by how dot assignment is lowered:
a = randn(3)
b = randn(3)
view(a,:) .= view(b,:) # this works
a .+= b # this works
view(a,:) .+= view(b,:) # this does not work
Unfortunately, Meta.@lower
doesn’t make me any wiser:
julia> Meta.@lower a .+= b
:($(Expr(:thunk, CodeInfo(
@ none within `top-level scope'
1 ─ %1 = Base.broadcasted(+, a, b)
│ %2 = Base.materialize!(a, %1)
└── return %2
))))
julia> Meta.@lower view(a,:) .= view(b,:)
:($(Expr(:thunk, CodeInfo(
@ none within `top-level scope'
1 ─ %1 = view(a, :)
│ %2 = view(b, :)
│ %3 = Base.broadcasted(Base.identity, %2)
│ %4 = Base.materialize!(%1, %3)
└── return %4
))))
julia> Meta.@lower view(a,:) .+= view(b,:)
:($(Expr(:error, "invalid assignment location \"view(a, :)\"")))
That’s a false-positive from the parser — I’d say that’s a bug. Mind filing an issue?
In this particular case, you can use @views a[:] .+= b[:]
to work around it (if this is indeed the form of your original problem that led you here).
Thanks for the response; issue filed here: https://github.com/JuliaLang/julia/issues/31295