Open cstjean opened 5 years ago
It is an interesting idea. AFAICT it was not discussed before. Some things that are challenging with this approach are:
Here is a super simple implementation without nested assignment support:
using Setfield: set, PropertyLens
mutable struct Mutable{T}
value::T
end
thaw(imut) = Mutable(imut)
freeze(mut::Mutable) = getfield(mut, :value)
Base.setproperty!(mut::Mutable, name::Symbol, value) =
setfield!(mut, :value, set(freeze(mut), PropertyLens{name}(), value))
Base.getproperty(mut::Mutable, name) = getproperty(freeze(mut), name)
It looks like the compiler can eliminate the allocation in a simple case like this:
f() = f((a=1,)).a
function f(x)
y = thaw(x)
y.a = 2
return freeze(y)
end
@code_typed optimize=true f()
prints
CodeInfo(
1 ─ return 2
) => Int64
- Change the type of the object
Maybe not being able to change the type is a feature in some sense? The user is signaling the compiler that the type never changes in this API. So it may be possible that the compiler has easier time inferring the code? This is just a speculation, though.
(I used thaw
/freeze
(inspired by https://github.com/JuliaLang/julia/pull/31630) instead of Ref
-like API because it also makes sense to wrap Tuple
/NamedTuple
/StaticArray
/etc. in this API.)
It occurred to me this morning that with the new
setproperty!/getproperty
methods, it might be possible to do something like:as syntax equivalent to
Internally,
o.obj
would contain the immutable, ando.f
(getproperty(o, :f)
) would return a proxy objectp
so thatp.x = 10
(setproperty(p, :x, 10)
) would be equivalent too.obj = @set o.f.x = 10
.It's not a great win over
@set
, which is already pretty concise. But I think for us it would be interesting, as it turns an immutable object into (what looks like) a regular mutable object, without any scary macro involved. Was that discussed anywhere?