General method for new structure

Hi,

I have made the CyclicArray type (https://github.com/udistr/CyclicArrays.jl) which defines a new structure:

struct CyclicArray{T,N} <: AbstractArray{T,N}
data::AbstractArray{T,N}
connections
end

Right now, I define many outer constructor methods that direct operations to the array, e.g.:

Base.size(A::CyclicArray) = size(A.data)

Is there a way to generalize this so that any function that expects one or more array arguments will perform its operation on the data array?

for example, if A is a CyclicArray type then any function f (e.g., sum, mean, size…), will be treated as:

f(A::CyclicArray) = f(A.data)

Similarly:

f(A::CyclicArray,B::CyclicArray) = f(A.data,B.data)

and so on.

Thanks,
Udi

Probably what you are searching for is this list of methods to implement:

https://docs.julialang.org/en/v1/manual/interfaces/#man-interface-array

A convenient way of delegating methods is Lazy.jl @forward. But there are other approaches:

1 Like

And if you need more than just forwarding, repetitive code can easily be generated with this pattern:

https://docs.julialang.org/en/v1/manual/metaprogramming/#Code-Generation

2 Likes

It is inconvenient to dig in these packages for the forward macro so I wrote my own version which just takes 10 lines and has no dependencies. This macro should be in an easier to reach place.

"""
@forward T.f f1,f2,...
  generates 
f1(a::T,args...)=f1(a.f,args...)
f2(a::T,args...)=f2(a.f,args...)
...
"""
macro forward(ex, fs)
  T, field = esc(ex.args[1]), ex.args[2].value
  fdefs=map(fs.args)do ff
      f= esc(ff)
      quote
        @inline ($f)(a::($T),args...)=($f)(a.$field,args...)
      end
  end
  Expr(:block, fdefs...)
end
1 Like