I am trying to understand how Base.@propagate_inbounds
works by studying its use in OffsetArrays.jl
. Currently setindex!
is implemented as
@propagate_inbounds function Base.setindex!(A::OffsetArray{T,N}, val, I::Vararg{Int,N}) where {T,N}
@boundscheck checkbounds(A, I...)
J = @inbounds map(parentindex, axes(A), I)
@inbounds parent(A)[J...] = val
val
end
However the use of @propagate_inbounds
here seems unnecessary to me, as the underlying parent array is indexed with @inbounds
anyway. Am I correct in this, and would it be the same if the @propagate_inbounds
macro is removed from the function definition?
It disables the @boundscheck
line if the caller used @inbounds
:
julia> using OffsetArrays
julia> o = OffsetVector([1, 2, 3], -1);
julia> function f(o)
@inbounds o[-1] = 1
return o
end
f (generic function with 1 method)
julia> function g(o)
o[-1] = 1
return o
end
g (generic function with 1 method)
julia> f(o)
3-element OffsetArray(::Array{Int64,1}, 0:2) with eltype Int64 with indices 0:2:
1
2
3
julia> g(o)
ERROR: BoundsError: attempt to access 3-element OffsetArray(::Array{Int64,1}, 0:2) with eltype Int64 with indices 0:2 at index [-1]
Stacktrace:
[1] throw_boundserror(::OffsetArray{Int64,1,Array{Int64,1}}, ::Tuple{Int64}) at ./abstractarray.jl:537
[2] checkbounds at ./abstractarray.jl:502 [inlined]
[3] setindex! at /home/fredrik/.julia/packages/OffsetArrays/JNUm0/src/OffsetArrays.jl:164 [inlined]
[4] g(::OffsetArray{Int64,1,Array{Int64,1}}) at ./REPL[4]:2
[5] top-level scope at REPL[6]:1
1 Like
Isn’t this what @inbounds
is supposed to do anyway if the function gets inlined? I understood @propagate_inbounds
to push the @inbounds
down one layer, but in this case the inner function is called with bounds checking disabled anyway, so propagating the @inbounds
should have no effect.
In other words, I understand if there’s an @inline
here, but the @propagate_inbounds
seems unnecessary. Is there something that I’m missing?