The code y = object.x binds a copy of object.x to y. How do I make bind y to object.x itself?
The reason for my question is this: To improve readability, I want to do something like this:
function foo(cache)
X = cache.X
y = cache.y
# lots of stuff involving X and y
end
The problem is that X or y is quite big and I don’t actually want to copy it (and I would like changes to X to be reflected in changes to cache.X) and do not want to clutter my code everywhere with “cache”.
At the beginning yes, but not for long if the OP does X = ... later in the code, if that’s what the OP meant by “changing” X. If cache.X is mutable and the “changes” are of the form X.field = value, then this will be automatically reflected in cache.X.field. The gist is if one wants to modify the value that cache.X is binded to, it’s not possible via X, but if the changes are to some deeper bindings in the structure of the data object that cache.X is binded to, e.g. cache.X.field = new_value, then one can alias cache.X and work with the new shorter name instead. So this pattern is not uncommon:
x = cache.x; y = cache.y;
...all sorts of acrobatics with x and y involving x = ... and y = ...
cache.x = x; cache.y = y; # to change the data objects that cache.x and cache.y are binded to only at the end
The 4 allocations here is just from the global scope, the bytes allocated is much fewer than would be needed to copy the array. If we want a copy, we need to specify it:
you are not mutating the value that object.x binds to, you are simply rebinding object.x to 2. The value object.x binds to a number and is immutable so there is no way to mutate that value.
I think the key issue here may be that you have a mental model of integers as mutable boxes and assume that assignment like this puts a different value in the box. That is not the case: integers are immutable and this assignment causes object.x to point at a different “box” containing the value 2; it does not mutate anything. The binding y still points at the “box” containing the value 1, which has not and cannot be changed because it is immutable.
To directly answer the original question, there is no general way to make the syntax x = ... have the same effect as a.b = .... However, if a.b refers to a mutable object, then doing x = a.b followed by mutating x has the same effect as mutating a.b.
Note that a.b = ... is a mutating operation on a. Something like push!(a.b, y) or a.b[1] = 0 would be a mutating operation on a.b.
I think those of us that come from C++ have a tendency to get super paranoid about copying and have a hard time trusting the compiler/garbage-collector to manage large objects sanely by default. Recently I created a whole package meant for managing large datasets entirely with pointers, only to realize that what I was trying to do works perfectly fine if done in the most naive way. I’ve come to the opinion that the best approach is to never worry about this sort of thing and to pick up the pieces later in the unlikely event that something goes horribly wrong. That approach will probably save a huge amount of wasted effort.
Out of curiosity, is there any future possibility (or possible already??) that it becomes possible to make
an alias to a variable of value (immutable) type, e.g. an integer variable? I mean something like ref nmol = systemFoo.numMolecules, where numMolecules is an integer variable
and nmol is an alias to it. Then, I can write a simpler code using nmol for brevity.
It is of course possible to create a binding with a shorter name like foo = systemFoo first,
but I feel it more convenient to be able to make an alias directly to numMolecules.
(In C++, I guess this is possible by auto& nmol = systemFoo.numMolecules. In Fortran, one can do
a similar thing like associate( nmol => systemFoo%numMolecules ) on the fly (with no declaration of nmol beforehand).
Revisiting the same question in a more convoluted example:
mutable struct Foo{T}
x::T
end
struct FooContainer{T}
x::Foo{T}
end
struct FooFooContainer{T}
x::FooContainer{T}
end
f = Foo(randn(10))
fc = FooContainer(f)
fcc = FooFooContainer(fc)
@allocated bar = f # 0
@allocated bar = fc.x # 0
@allocated bar = fcc.x # not 0!
How do I get the last line to be non-allocating, i.e. aliasing?