Nested getproperty requests

I have a use for accessing and setting nested properties of julia objects. To achieve this, I have the code below in a package. I have been reasonably accused of type piracy and wondered: (i) if others agree this is dangerous to implement, and (ii) whether julia language developers might conceivably view it as an extension to the language:

"""
    getproperty(object, nested_name::Expr)

Call getproperty recursively on `object` to extract the value of some
nested property, as in the following example:

    julia> object = (X = (x = 1, y = 2), Y = 3)
    julia> getproperty(object, :(X.y))
    2

"""
function Base.getproperty(obj, ex::Expr)
    subex, field = reduce_nested_field(ex)
    return getproperty(getproperty(obj, subex), field)
end

"""
    setproperty!(object, nested_name::Expr, value)

Set a nested property of an `object` to `value`, as in the following example:

    julia> mutable struct Foo
               X
               Y
           end

    julia> mutable struct Bar
               x
               y
           end

    julia> object = Foo(Bar(1, 2), 3)
    Foo(Bar(1, 2), 3)

    julia> setproperty!(object, :(X.y), 42)
    42

    julia> object 
    Foo(Bar(1, 42), 3)


"""
function Base.setproperty!(obj, ex::Expr, value)
    subex, field = reduce_nested_field(ex)
    last_obj = getproperty(obj, subex)
    return setproperty!(last_obj, field, value)
end

# applying the following to `:(a.b.c)` returns `(:(a.b), :c)`
function reduce_nested_field(ex)
    ex.head == :. || throw(ArgumentError)
    tail = ex.args[2]
    tail isa QuoteNode || throw(ArgumentError)
    field = tail.value
    field isa Symbol || throw(ArgmentError)
    subex = ex.args[1]
    return (subex, field)
end

I highly recommend looking at Setfield.jl which is implemented based on very elegant and simple lens API. Its primary focus is on the immutable data structures at this point but it should not be difficult to extend to in-place operations. Discussion on the support for mutable data structure is happening in https://github.com/jw3126/Setfield.jl/issues/32

4 Likes

Maybe of interest https://youtu.be/vWZzmV7mHiw