Accessors.jl icon indicating copy to clipboard operation
Accessors.jl copied to clipboard

minimum implementation for type wrapping a NamedTuple

Open tpapp opened this issue 2 months ago • 4 comments

I have a type wrapping a NamedTuple, that essentially forwards getproperty. For the purposes of the MWE, let it be

struct WrapNT{NT<:NamedTuple}
    nt::NT
    count::Int # for the purposes of the MWE, maintain as length(nt)
end

@inline _nt(wnt::WrapNT) = getfield(wnt, :nt) # save typing

Base.show(io::IO, wnt::WrapNT) = print(getfield(wnt, :count), " fields ", _nt(wnt))

# constructor
wrap_NT(nt::NamedTuple) = WrapNT(nt, length(nt))

Base.propertynames(wnt::WrapNT) = propertynames(_nt(wnt))

Base.getproperty(wnt::WrapNT, sym::Symbol) = getproperty(_nt(wnt), sym)

The question is: how should I hook into the API of Accessors.jl so that stuff "just works"? I experimented and found that

function Accessors.insert(wnt::WrapNT, lens::PropertyLens{S}, val) where S
    wrap_NT(Accessors.insert(_nt(wnt), lens, val))
end

function Accessors.set(wnt::WrapNT, lens::PropertyLens{S}, val) where S
    wrap_NT(Accessors.set(_nt(wnt), lens, val))
end

function Accessors.delete(wnt::WrapNT, lens::PropertyLens{S}) where S
    wrap_NT(Accessors.delete(_nt(wnt), lens))
end

works, but from the manual it is not clear if this is enough.

tpapp avatar Oct 07 '25 12:10 tpapp

The most convenient way is to define a setter for your _nt function first, and use it to forward set/insert/delete:

Accessors.set(wnt::WrapNT, ::typeof(_nt), nt) = wrap_NT(nt)

Accessors.set(wnt::WrapNT, lens::PropertyLens, val) = set(wnt, lens ∘ _nt, val)
Accessors.insert(wnt::WrapNT, lens::PropertyLens, val) = insert(wnt, lens ∘ _nt, val)
Accessors.delete(wnt::WrapNT, lens::PropertyLens) = delete(wnt, lens ∘ _nt)

aplavin avatar Oct 07 '25 12:10 aplavin

Thanks! I am assuming you meant delete without the val argument.

This works just great. If you think the manual would benefit from a PR, I would be happy to make one using this example.

tpapp avatar Oct 07 '25 13:10 tpapp

It would be cool to have something like MacroTools.@forward for writing these methods automatically!

cstjean avatar Oct 10 '25 02:10 cstjean

Indeed! We already have a convenience tool for that, but it doesn't apply to PropertyLens specifically: @accessor myfunc(x) = x.myfield enables set/insert/delete on myfunc. Maybe, @accessor Base.getproperty(...) = ... should have special handling and forward ::PropertyLens?..

aplavin avatar Oct 10 '25 11:10 aplavin