udistr
December 11, 2020, 2:07pm
1
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
lmiq
December 11, 2020, 2:12pm
2
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:
MacroTools.jl defines a @forward macro but it’s in the examples folder .
Lazy.jl exports its own version of the same macro but it’s not documented in the README.
Come to think of it, while the @forward macro is quite useful, it isn’t really a macro development tool nor a functional programming tool. So I’m not too surprised that it is treated like a second-class citizen in those packages.
Any thought about what kind of package would be a good fit for this?
1 Like
FPGro
December 11, 2020, 4:00pm
4
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