Question regarding references

question

#1

Could someone please help me understand references a bit better :thinking:. I see several related questions have been asked and answered. I read them over and they did help a bit but I’m still not sure how to do what I would like.

I have a fairly complicated tree of structures containing various data types that may need changed based upon references from arbitrary points within the tree.
To create an example without the tree:

julia> A = 5
5
julia> B = A
5
julia> B === A
true

However, I obviously cannot assign a value to B in the following way:

julia> B = 3

Because I am saying that B is now a number instead of a reference to A. At least that is my understanding… What I do not see is how I can assign 3 to A through B. I hope I am explaining myself clearly.

I would really appreciate any help I can get on this. It’s probably something simple :roll_eyes:. Thanks!


#2

Have you read this?
http://www.johnmyleswhite.com/notebook/2014/09/06/values-vs-bindings-the-map-is-not-the-territory/


#3

I believe I have read that some time back but it has a few details that I had forgotten about. Great information, Thanks! I am still not sure how to deal with my specific case though. Much of the information in that article focuses on a specific case (arrays). It may apply to my question but I don’t see how because A could represent a value in an Array or not and B is not an Array.

I would like to assign to A using B …so that when I assign to B the value of A is changed.

Thanks again for pointing that blog out to me.


#4

Can you specify more structure about your problem?

I am assuming that you are using some sort of container, eg

mutable struct C{T}
    x::T 
end

A = C(1)
B = A
A.x = 2
B # now has 2

#5

Sure, here’s an example:

# Ok, my container looks something like this:

julia> mutable struct NodeInTree
           w::Array{Int64,1}
           x::Int64 
           y::Any
       end

# a tree would be composed of nodes that are mostly similer.
julia> nodeOne = NodeInTree( [1,2,3], 25, nothing )
NodeInTree([1, 2, 3], 25, nothing)

julia> nodeTwo = NodeInTree( [4,5,6], 50, nodeOne.w[2] )
NodeInTree([4, 5, 6], 50, 2)

# Now we can add in that missing binding...
julia> nodeOne.y = nodeTwo.x
50

# we can see they are identical:
julia> nodeOne.y === nodeTwo.x
true

# However upon assignment...
julia> nodeTwo.x = 3
3

julia> nodeOne.y
50

julia> nodeOne.y === nodeTwo.x
false


#6

If I understand your problem correctly, making x and y container types, eg Ref, or something defined for the purpose like my C above, may help.


#7

To follow on with @Tamas_Papp’s advice, the summary is that, no matter what, doing B = 2 will never change the contents of some other variable. The only thing it does is apply the label “B” to a new value, regardless of what that label used to be applied to. On the other hand, mutating the contents of B can affect the contents of A, if they refer to the same mutable object. You can mutate contents by, for example, setting an array element, setting a Ref, or setting an object field.

All of the following are ways to achieve what you want:

  • use an Array:
julia> A = [1]
1-element Array{Int64,1}:
 1

julia> B = A
1-element Array{Int64,1}:
 1

julia> B[1] = 5
5

julia> A[1]
5
  • use a Ref (similar to a zero-dimensional Array holding one object)
julia> A = Ref(1)
Base.RefValue{Int64}(1)

julia> B = A
Base.RefValue{Int64}(1)

julia> B[] = 5
5

julia> A
Base.RefValue{Int64}(5)

julia> A[]
5
  • use a container and mutate its contents
julia> mutable struct Foo
         x::Int
       end

julia> A = Foo(1)
Foo(1)

julia> B = A
Foo(1)

julia> B.x = 5
5

julia> A.x
5

the key here is that all of the ways that work involve mutating an object or changing its contents with B[] = 5 or B[1] = 5 or B.x = 5. None of them involve re-assigning B = 5 because that would just apply the B label to a brand-new piece of data, losing all connection between what the B and A labels mean.


#8

Ok, that makes sense. It looks like you both have cleared up my misunderstanding. Thanks so much for heping me :smile: From your examples there @rdeits I think I can see where I had gone wrong.

If I understand correctly (from both of you) I cannot treat a simple variable as a reference …it must be a container!


#9

I wrote about much the same thing on StackOverflow a while ago: