How does broadcasting work for a vector of `RefArray`s?

Hello. I’m having some trouble understanding Julia’s broadcast behaviour on a specific scenario.

The following code works as expected:

julia> a = [1, 2, 3];

julia> refs = [Ref(a, i) for i in eachindex(a)];

julia> refs[1][] = 0;

julia> refs[2][] = 0;

julia> a
3-element Vector{Int64}:
 0
 0
 3

But brodcasting the operation via @. gives an error.

julia> @. refs[1:2][] = 0
ERROR: BoundsError: attempt to access 2-element Vector{Base.RefArray{Int64, Vector{Int64}, Nothing}} at index []
Stacktrace:
 [1] throw_boundserror(A::Vector{Base.RefArray{Int64, Vector{Int64}, Nothing}}, I::Tuple{})
   @ Base ./abstractarray.jl:703
 [2] checkbounds
   @ ./abstractarray.jl:668 [inlined]
 [3] _getindex
   @ ./abstractarray.jl:1273 [inlined]
 [4] getindex
   @ ./abstractarray.jl:1241 [inlined]
 [5] maybeview
   @ ./views.jl:149 [inlined]
 [6] dotview(args::Vector{Base.RefArray{Int64, Vector{Int64}, Nothing}})
   @ Base.Broadcast ./broadcast.jl:1201
 [7] top-level scope
   @ REPL[7]:1

I’m aware that one can achieve the desired effect via setindex!., but I’m still interested in better understanding where the error comes from (I guess it has to do with the broadcast dereferencing things that I don’t want it to). For example, is there a way to use $ to make the @. line work?

Thank you!

The macro @. only broadcasts function calls or operators; it does not work with indexing or dereferencing. So you are having the same error as if you just typed the left hand side of the operation:

refs[1:2][]
1 Like

I see. IDK why, but I was expecting @. to do a something more ellaborate. My bad.
That was a quick one. Thank you!

if you use the setindex!() function as defined in refpointer.jl

a = [1, 2, 3];
refs = [Ref(a, i) for i in eachindex(a)]
struct RefArray{T,A<:AbstractArray{T},R} <: Ref{T}
    x::A
    i::Int
    roots::R # should be either ::Nothing or ::Any
    RefArray{T,A,R}(x,i,roots=nothing) where {T,A<:AbstractArray{T},R} = new(x,i,roots)
end

Base.setindex!(b::RefArray, x) = (b.x[b.i] = x; b)

@. setindex!(refs[1:2],-1)
julia> a
3-element Vector{Int64}:
 -1
 -1
  3