A gotcha with OffsetArrays

With

using OffsetArrays

import Base: length, size, lastindex, firstindex, eachindex, getindex, setindex!, show, display

struct Polly{T} <: AbstractVector{ T }
    d   :: Int
    a   :: OffsetArray{ T, 1 }

    function Polly( d :: Int, 𝒯::Type{T} = BigInt ) where T
        d ≥ 0 || error( "Need d ≥ 0, but d = $d" )
        return new{T}( d, OffsetArray( vcat( ones( T, 1 ), zeros( T, d ) ), 0:d ) )
    end
end


length( p :: Polly ) = length( p.a )
size( p :: Polly ) = size( p.a )
size( p :: Polly, j  ) = size( p.a, j )
lastindex( p :: Polly ) = lastindex( p.a )
firstindex( p :: Polly ) = firstindex( p.a )
eachindex( p :: Polly ) = firstindex( p ) : lastindex( p )
getindex( p :: Polly, j :: Int ) = getindex( p.a, j )

function setindex!( p :: Polly{T}, x :: T, j :: Int ) where T
    j ∈ eachindex( p ) && return setindex!( p.a, x, j )
    j < 0 && error( "Cannot deal with negative indices" )
    append!( p.a, zeros( T, j - length( p)))
    setindex!( p.a, x, j )
    p.d = j + 1
    return x
end

x = Polly( 4, Rational{BigInt} )

I get

  0
   0
   0
   0
 #undef

whereas I had expected the first element to be one given that eachindex is defined. I can solve the problem by overloading show and display but is there a cleaner solution?

Thanks!

It appears that OffsetArrays uses Base.replace_in_print_matrix to address the same problem; this is a method that I’m not familiar with.

No, I think you’re just missing a Base.axes(p::Polly) = axes(p.a). And then you don’t need to define firstindex/lastindex/eachindex.

2 Likes

Wow: thanks!