ForwardMethods.array_interfaceMethod
ForwardMethods.array_interface(T; index_style_linear::Bool, omit=Symbol[])

Forwards the following methods for x::T:

  • Base.size(x::T)
  • Base.iterate(x::T)
  • Base.iterate(x::T, state)
  • Base.length(x::T)
  • Base.IndexStyle(::Type{T})
  • Base.getindex(x::T, index)
  • Base.setindex!(x::T, value, index)

The signatures for Base.getindex + Base.setindex! will be set according to the value of index_style_linear

Any function names specified in omit::AbstractVector{Symbol} will not be defined

ForwardMethods.dict_interfaceMethod
ForwardMethods.dict_interface(T; omit=Symbol[])

Forwards the following methods for x::T:

  • Base.keys(x::T)
  • Base.values(x::T)
  • Base.pairs(x::T)
  • Base.length(x::T)
  • Base.isempty(x::T)
  • Base.empty!(x::T)
  • Base.iterate(x::T)
  • Base.iterate(x::T, state)
  • Base.pop!(x::T, key)
  • Base.delete!(x::T, key)
  • Base.haskey(x::T, key)
  • Base.getindex(x::T, key)
  • Base.setindex!(x::T, value, key)
  • Base.get(x::T, key, default_value)
  • Base.get!(default::Callable, x::T, key)
  • Base.in(value, x::T)

Any function names specified in omit::AbstractVector{Symbol} will not be defined

ForwardMethods.equality_interfaceMethod
equality_interface(T; [omit=Symbol[], equality_op=:(==), compare_fields=:fieldnames])

Defines the equality_op operator for two objects of type T in the natural way, i.e.,

    Base.:(==)(x::T, y::T) = all( getfield(x,k) == getfield(y,k) for k in fieldnames(T))

Arguments

If equality_op == isequal, defines Base.isequal instead.

If compare_fields == propertynames, the above definition uses getproperty and propertynames(x) instead of getfield and fieldnames(T), respectively.

Any values provided in omit are excluded from the generator expression above.

ForwardMethods.getfields_interfaceMethod
getfields_interface(T; omit=Symbol[])

Given x::T, forwards the method $field(x::T) to getfield(x, $field), for each field in fieldnames(T)

ForwardMethods.indexing_interfaceMethod
ForwardMethods.indexing_interface(T; omit=Symbol[])

Forwards the following methods for x::T:

  • Base.getindex(x::T, index)
  • Base.setindex!(x::T, value, index)
  • Base.firstindex(x::T)
  • Base.lastindex(x::T)

Any function names specified in omit::AbstractVector{Symbol} will not be defined

ForwardMethods.iteration_interfaceMethod
ForwardMethods.iteration_interface(T; omit=Symbol[])

Forwards the following methods for x::T:

  • Base.iterate(x::T)
  • Base.iterate(x::T, state)
  • Base.IteratorSize(::Type{T})
  • Base.IteratorEltype(::Type{T})
  • Base.eltype(::Type{T})
  • Base.length(x::T)
  • Base.size(x::T)
  • Base.isdone(x::T)
  • Base.isdone(x::T, state)

Any function names specified in omit::AbstractVector{Symbol} will not be defined

ForwardMethods.lockable_interfaceMethod
ForwardMethods.lockable_interface(T; omit=Symbol[])

Forwards the following methods for x::T:

  • Base.lock(x::T)
  • Base.lock(f, x::T)
  • Base.unlock(x::T)
  • Base.trylock(x::T)
  • Base.islocked(x::T)

Any function names specified in omit::AbstractVector{Symbol} will not be defined

ForwardMethods.properties_interfaceMethod
properties_interface(T; delegated_fields, [recursive::Bool=false], [ensure_unique::Bool=true])

Provides amalgamated property-based access to x::T in terms of its fields as well as the fields of its children. So that, i.e., the fact that x is composed of fields k1::T1, k2::T2, ..., kn::Tn becomes an implementation detail of the construction of x.

More specifically, given the set of symbols delegated_fields and x::T for a struct type T, defines:

  • Base.propertynames(x::T) in terms of fieldnames(T), as well as the fieldnames of getfield(x, k) for each k in delegated_fields.
  • Base.getproperty(x::T, name::Symbol) to return getfield(getfield(x, k), name) for the first k ∈ delegated_fields such that hasfield(getfield(x, k), name). If no such k exists, defaults to returning getfield(x, name).
  • and analogously for Base.setproperty!(x::T, name::Symbol, value)

If recursive == true, instances of getfield/hasfield/setfield in the above are replaced by internal methods that default to Base.getproperty/Base.setproperty/Base.hasproperty, respectively.

If ensure_unique == true, throws an error when there are nonunique names in the amalgamation of the fields of x with the fields/recursive properties of each field in delegated_fields. If this option is false, any of the above setting/getting operations above will use the first (possibly recursive) child field found matching the above criteria.

Arguments

delegated_fields can be either a Symbol, or a vect or tuple Expr of Symbols, corresponding to fieldnames of T

ForwardMethods.setfields_interfaceMethod
setfields_interface(T; omit=Symbol[])

Given x::T, forwards the method $field!(x::T, value) to setfield!(x, $field, value), for each field in fieldnames(T)

ForwardMethods.vector_interfaceMethod
ForwardMethods.vector_interface(T; omit=Symbol[])

Forwards the methods for x::T from ForwardMethods.array_interface(T; index_style_linear=true), ForwardMethods.iteration_interface(T), and ForwardMethods.indexing_interface(T)

Any function names specified in omit::AbstractVector{Symbol} will not be defined.

ForwardMethods.@define_interfaceMacro
@define_interface T [interface=name] [kwargs...]

Defines the interface for objects of type T

Arguments

name must be one of (:properties, :equality, :setfields, :getfields), with name value f corresponding to the interface definition function $f_interface (e.g., array => array_interface).

The key=value pairs will be forwarded to the corresponding interface definition method. In particular, specifying omit=func1 or omit=[func1,func2, ..., funcn] will omit func1, ..., funcn from being forwarded by this macro.

Refer to the documentation of each name_interface for the specific keyword arguments required, if any.

ForwardMethods.@forward_interfaceMacro
@forward_interface T [field=_field] [interface=name] [map=_map] [key=value...]

Forwards the methods defined for interface to objects of type T

Arguments

name must be one of (:iteration, :indexing, :array, :vector, :dict, :lockable, :getfields, :setfields), with name value f corresponding to the interface definition function $f_interface (e.g., array => array_interface).

If name is either getfields or setfields, then the field keyword argument is ignored

Otherwise, _field must be one of the following expressions

  • k::Symbol or k::QuoteNode, or an expression of the form getfield(_, k), in which case methods will be forwarded to getfield(x, k)
  • an expression of the form getproperty(_, k), in which case methods will be forwarded to getproperty(x, k)
  • an expression of the form t[args...], in which case methods will be forwarded to x[args...]
  • or an expression of the form f(_) for a single-argument function f, in which case methods will be forwarded to f(x)

Additional Arguments

The key=value pairs will be forwarded to the corresponding interface definition method. In particular, specifying omit=func1 or omit=[func1,func2, ..., funcn] will omit func1, ..., funcn from being forwarded by this macro.

See also @forward_methods

ForwardMethods.@forward_methodsMacro
@forward_methods T [field=_field] [map=_map] methods...

Forwards the method definitions for x::T, depending on the value of _field.

_field must be one of the following expressions

  • k::Symbol or k::QuoteNode, or an expression of the form getfield(_, k), in which case methods will be forwarded to getfield(x, k)
  • an expression of the form a.b.c. ..., in which case methods will be forwarded to getfield(getfield(getfield(x, :a), :b), :c) ...
  • an expression of the form getproperty(_, k), in which case methods will be forwarded to getproperty(x, k)
  • an expression of the form t[args...], in which case methods will be forwarded to x[args...]
  • or an expression of the form f(_) for a single-argument function f, in which case methods will be forwarded to f(x)

For notational purposes below, call the forwarded value forwarded_value(x).

Each method must be one of the following expressions

  • an expression of the form f::Symbol or A.f, which will forward the single-argument function f(x) or A.f(x) to f(forwarded_value(x)) or A.f(forwarded_value(x)), respectively

  • a function signature of the form f(args...), or f(args...; kwargs...). In this form, there must be either exactly one expression of the form x::T or _ (an underscore) in args. If this occurs at position i, say, this macro will forward this method to the definition

    f(args[1], args[2], ..., args[i-1], forwarded_value(x), args[i+1], ..., args[end]; kwargs...)

    When field maps to invoking getfield for field k, one can also write an argument expression of the form ::T or x::T. In this case, this macro definition will define

    f(args[1], ..., args[i-1], ::Type{T}, args[i+1], ..., args[end]; kwargs) = f(args[1], ..., args[i-1], fieldtype(T, k), args[i+1], ..., args[end]; kwargs)

    which can be useful for forwarding, for instance, trait-based methods to the corresponding container type.

Optional Arguments

The optional map=_map parameter allows you to apply an expression transformation to the resulting forwarded expression. _map must be an expression containing at least one underscore _ placeholder and optionally _obj placeholders. _ and _obj will be replaced with the transformed function and initial object argument, respectively.

For example, if we have

    struct LockableDict{K,V}
        d::Dict{K,V}
        lock::ReentrantLock
    end
    @forward LockableDict{K,V} field=lock Base.lock Base.unlock
    @forward LockableDict{K,V} field=d map=(begin lock(_obj); try _ finally unlock(_obj) end end) Base.getindex(_, k) 

Then the expressions generated in the second statement are (roughly) of the form

    function Base.getindex(l::LockableDict{K,V}, k)
        lock(l)
        try 
            Base.getindex(getfield(l, :d))
        finally
            unlock(l)
        end
    end

Notes

  • Parametric expressions are supported for T, as well as for the function signature form of method

Examples

julia> struct B{T} 
         v::Vector{T}
       end

julia> @forward_methods B{T} field=v Base.firstindex Base.lastindex Base.getindex(_, k::Int) Base.setindex!(x::B, v, k) (Base.eachindex(x::B{T}) where {T})

julia> b = B([1,2,3])
B{Int64}([1, 2, 3])

julia> for i in eachindex(b)
         b[i] = b[i]^2
       end
julia> b[end]
9

julia> struct C
         d::Dict{String,Int}
       end
julia> @forward_methods C field=d Base.keytype(::Type{C}) Base.valtype(::Type{C})

julia> keytype(C)
String 

julia> valtype(C)
Int