Can you only define some fields in an object constant or immutable, as in C++ class Foo { int x; cont int y; };
?
One thing you could do is define an immutable struct in which some of the (immutable) fields are wrapped in Ref
s to make them mutable:
julia> struct Foo
x :: Ref{Int}
y :: Int
end
julia> f = Foo(1, 2)
Foo(Base.RefValue{Int64}(1), 2)
julia> f.x[] += 10 # OK: mutate the Ref
11
julia> f.y += 10
ERROR: setfield! immutable struct of type Foo cannot be changed
Stacktrace:
[1] setproperty!(x::Foo, f::Symbol, v::Int64)
@ Base ./Base.jl:34
[2] top-level scope
@ REPL[4]:1
In terms of syntax, it does however change the way Ref
-wrapped fields are accessed, since you have to put square brackets to access the value itself (f.x[]
instead of simply f.x
if it were directly an Int
).
Note that Ref
is an abstract type:
julia> typeof(Ref(1))
Base.RefValue{Int64}
So for performance reasons you might want to use Base.RefValue
instead.
The strict answer would be no, you can’t define some fields to be mutable because the concept of mutable types in Julia is different from C++.
But it is possible to make it look like that. One way is already mentioned, make “mutable” fields hold a container, another is to overload setproperty!
for a mutable type so that it works only on certain fields:
struct SemiMutable1
x::Base.RefValue{Int}
y::Int
end
# to avoid [] for field access
function Base.getproperty(val::SemiMutable1, p::Symbol)
if p === :x
return getfield(val, :x)[]
else
return getfield(val, p)
end
end
function Base.setproperty!(val::SemiMutable1, p::Symbol, x)
if p === :x
return getfield(val, :x)[] = x
else
return setfield!(val, p, x)
end
end
mutable struct SemiMutable2
x::Int
y::Int
end
function Base.setproperty!(val::SemiMutable2, p::Symbol, x)
if p === :x
return setfield!(val, :x, x)
else
error("field `y` of `SemiMutable2` cannot be changed")
end
end
Here is a discussion of many alternatives: Mutable scalar in immutable object: the best alternative?
I understand your question, I’m just thinking is it a mistake or anti-pattern to ever do this? So do you have a more concrete example/reason to do this?
If it’s just out of curiosity, and possibly unfamiliarity with Julia (it’s not clear for how long you’ve used Julia), then FYI: struct
s are immutable (by default) in Julia, ALSO, strictly, in the answers given. I used to like that Julia is an imperative language, i.e. not a pure functional by default.
Maybe @nben’s package can help you:
I can’t recommend Hickey’s talk highly enough on what’s wrong with almost all “information” systems (regarding what he calls place-oriented programming, which implies imperative, almost a synonym, it seems imperative is maybe more general, on how to implement the former).
If it seems long, or you only have a limited amount of time, I recommend giving it a change for even just the first 3-18 min. to see if it’s of interest.
I watched this talk recently, and then immediately again it’s that good, I would say required for all programmers. Note, do not watch it full-screen. I missed out on the slides the first time. That was only part of the reason to watch again, to check if I missed something there. I wouldn’t say it was needed, it was all very clear.
Julia immutable be default in lots of ways, strings, structs, but not arrays/containers, e.g. Dict
s. but Air.jl fixes that for all (included in the standard library, in both missing mainly ordered Dict
s), the important data structures and arrays
You have a typo cont->const, consider editing your post and doing this way:
julia> mutable struct Foo
x::Int
__y::Int
end
Then x is mutable, more like in C++, while actually __y too (but __ prefix means stay away), i.e. the whole struct
. Yes, that’s place-oriented-programming (PLOP)… what you aim for is only half that, a half-sin, and I’m not really sure it’s better. So also consider fully immutable, the default, that you can still use with arrays, but then again you’re back to PLOP. PArray
would fix that.