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
.