Using OffsetArrays within a struct causes AbstractVector type

I’m putting offset arrays in a struct and it is causing a type warning and slow performance.

Here is a MWE

module test 

using Parameters 
using OffsetArrays

# Define struct with standard vector and offset vector
@with_kw struct mesh_struct
    xv :: Vector{Float64}
    xo :: OffsetArrays.OffsetVector{Float64}
end

# Function that uses mesh
function solver(mesh)
    println(mesh.xv)
    println(mesh.xo)
end

end

using OffsetArrays

# Create test vectors
xv=rand(3);
xo=OffsetArray(xv,0)

# Put in struct
mesh = test.mesh_struct(
    xv=xv,
    xo=xo,
)
# Run solver to make sure there are no errors
test.solver(mesh)

# Check types
@code_warntype test.solver(mesh)

Which outputs

[0.24265431337818855, 0.573748386651149, 0.5192484993762961]
[0.24265431337818855, 0.573748386651149, 0.5192484993762961]
MethodInstance for Main.test.solver(::Main.test.mesh_struct)
  from solver(mesh) in Main.test at /Users/mowkes/.julia/dev/NavierStokes_Parallel/src/test.jl:13
Arguments
  #self#::Core.Const(Main.test.solver)
  mesh::Main.test.mesh_struct
Body::Nothing
1 ─ %1 = Base.getproperty(mesh, :xv)::Vector{Float64}
│        Main.test.println(%1)
│   %3 = Base.getproperty(mesh, :xo)::OffsetVector{Float64, AA} where AA<:AbstractVector{Float64}
│   %4 = Main.test.println(%3)::Core.Const(nothing)
└──      return %4

The OffsetVector{Float64, AA} where AA<:AbstractVector{Float64} part of the output is in red.

julia> typeof(xo)
OffsetVector{Float64, Vector{Float64}} (alias for OffsetArray{Float64, 1, Array{Float64, 1}})

You’ll need to specify the full type OffsetVector{Float64, Vector{Float64}} in your struct if you want type-stability. You may also parameterize the struct, in case you don’t want to be this explicit.

2 Likes

Yes, the full concrete type for OffsetArrays is somewhat unwieldy.

Often I want OffsetArrays backed by standard arrays.
For those cases I define:

const OArray{T,N} = OffsetArray{T, N, Array{T,N}}
const OVector{T}  = OffsetArray{T, 1, Array{T,1}}
const OMatrix{T}  = OffsetArray{T, 2, Array{T,2}}

Then I can define offset arrays with similar syntax to standard arrays:

struct MyStruct
    x::OVector{Float64}
    y::OArray{Int,3}
end
4 Likes