JuliaObjects / Accessors.jl

Update immutable data
Other
173 stars 17 forks source link

`hasproperty()` analogue for optics #92

Open staticfloat opened 1 year ago

staticfloat commented 1 year ago

Sometimes I'd like to check beforehand whether an optic is truly applicable to a type; especially when dealing with deeply-nested optics. It would be quite useful if there existed a hasproperty() analogue for optics on a type. I've made a simple version for PropertyLens and ComposedFunction, but I'm not sure about the rest of the optic types. I'm opening this issue so that if someone else is interested, they can carry this to completion.

function Base.hasproperty(x, o::PropertyLens)
    return typeof(o).parameters[1] ∈ propertynames(x)
end
function Base.hasproperty(x, o::ComposedFunction)
    return hasproperty(x, o.outer) &&
           hasproperty(o.outer(x), o.inner)
end

This allows tests such as the following:

using Accessors

struct T
    a
    b
end

x = T(T(1,2), 3)

@show hasproperty(x, @optic _.a)
@show hasproperty(x, @optic _.b)
@show hasproperty(x, @optic _.c)
@show hasproperty(x, @optic _.a.a)
@show hasproperty(x, @optic _.a.a.a)
@show hasproperty(x, @optic _.b.a)
jw3126 commented 1 year ago

Thanks @staticfloat ! Would be nice to have such functionality. I thing it should however not be a method of Base.hasproperty. One reason is that it can be generalized to handle other lenses like IndexLens and then the name makes less sense. The other reason is that overloads like Base.hasproperty(x, o::ComposedFunction) are type piracy.

aplavin commented 1 year ago

This function is now available as hasoptic(obj, optic)::Bool in AccessorsExtra. Also, see maybe(optic) there: it's often more convenient than manually handling has/hasn't cases. I think more real-world usage and testing of the interface is needed before inclusion in Accessors proper (or it shouldn't be included here at all).

aplavin commented 1 year ago

I've been using maybe-optics for some time already, and quite like them. They are based on hasoptic check, through I didn't really find myself using this check explicitly. Would be nice to include into Accessors proper at some point, but there are a few questions on the semantics of hasoptic and of maybe. Here's a list of concerns about the "get" part alone: