Suppose I have the following mutable struct
@kwdef mutable struct Rectangle{T}
x::T = 0
y::T = 0
function Rectangle(args...)
return new{promote_type(typeof.(args)...)}(args...)
end
end
I would like for this struct to have two additional properties, 1) area
which is read-only, and 2) square
which is write-only and sets both x
and y
:
function Base.getproperty(r::Rectangle, key::Symbol)
if key == :area
return r.x*r.y
elseif key == :square
error("Property :square is write-only for Rectangle")
else
return getfield(r, key)
end
end
function Base.setproperty!(r::Rectangle{T}, key::Symbol, val) where {T}
if key == :area
error("Property :area is read-only for Rectangle")
elseif key == :square
r.x = val
r.y = val
return val
else
return setfield!(r, key, T(val))
end
end
Even though this is a mutable struct, I have a general framework which only creates new promoted structs if the type of a field is set to a value which requires type promotion. This makes use of the super powerful Accessors.jl . E.g.
r = Rectangle(1.0, 2.0)
r.x = 1im # error because r isa Rectangle{Float64}
using Accessors
@reset r.x = 1im # works!
The problem is if a user tries to (re)set a the write-only field including promotion:
r = Rectangle(3.0,4.0)
r.square = 5.0 # fine
r.x == r.y == 5.0 # true
@reset r.square = 2.0im
# ERROR: ArgumentError: Failed to assign fields (:square,) to object with fields (:x, :y).
With this error, and with some reading of ConstructionBase.jl documentation, I currently have two questions:
- How should I override
Base.propertynames
for the case where some properties are write-only and some read-only? - The documentation suggests that I should override
ConstructionBase.setproperties
(andConstructionBase.getproperties
?) however in the documentation for these functions I see the requirement:
3. setproperties is defined in relation to getproperties so that:
obj == setproperties(obj, getproperties(obj))
How do I handle this when some properties are write-only and some read-only?