Help with `Base.getproperty` syntax

I am trying to add Base.property methods to my own types for the first time and hitting a wall. Here’s a minimal example:

module A
    import Base.getproperty

    struct S
        x
    end

    Base.getproperty(x::S, ::Val{:a}) = "a"
end

obj = A.S(1)
obj.a

This gives the error:

ERROR: type S has no field a
Stacktrace:
 [1] getproperty(::Any, ::Symbol) at ./sysimg.jl:18

I am on Julia 1.0.1 on OSX. Thanks for any suggestions.

2 Likes
julia> struct S
           x
       end

julia> function Base.getproperty(x::S, sym::Symbol)
           if sym == :a
               "a"
           else
               # fallback to getfield
               getfield(x, sym)
           end
       end

julia> obj = S(1)
S(1)

julia> obj.a
"a"

julia> obj.x
1

julia> obj.y
ERROR: type S has no field y
Stacktrace:
 [1] getproperty(::S, ::Symbol) at ./REPL[2]:6
4 Likes

Note that this seems to be broken on master… https://github.com/JuliaLang/julia/issues/29761

(Note that due to ongoing GitHub issues, you may see that link as a 404—I do.)

You can still dispatch on the property name with

_getproperty(x::S, ::Val{s}) where {s} = getfield(x, s)
_getproperty(x::S, ::Val{:a}) = "a"

Base.getproperty(x::S, s::Symbol) = _getproperty(x, Val{s}())

However, you should only do this if you have a small number of property names, as there’s lots of potential for performance issues. It’s also a good idea to provide methods for Base.propertynames.

3 Likes

Thank you for the solution. Is this the intended way to use Base.getproperty or a workaround for a current issue? I would have had a hard time figuring this out from the docs. If it’s intended, I’ll submit a PR for the Julia docs.

It is the intended way, cf

help?> getproperty
search: getproperty

  getproperty(value, name::Symbol)

  The syntax a.b calls getproperty(a, :b).

  See also propertynames and setproperty!.
3 Likes

Thank you, added your tip here https://github.com/JuliaLang/julia/pull/29771

1 Like