I have a list of reference class objects and I expect that when I change one of the objects the list was initialized with, the corresponding entry in the list should also change. This is not the case, as indicated in the following example code, if I make a list of square
and triangle
and then I change square
to octagon
. The list will still have polygons of 4 and 3 sides respectively. The same is true the other way around. If I change the element of the list, the initial variable remains unchanged. Does anyone know why this is or if there is a way around it? Thanks!
Polygon <- setRefClass("Polygon", fields = c("sides"))
square <- Polygon$new(sides = 4)
triangle <- Polygon$new(sides = 3)
octagon <- Polygon$new(sides = 8)
pList <-list(square,triangle)
print(pList)
# [[1]] Reference class object of class "Polygon"
# Field "sides": [1] 4
# [[2]] # Reference class object of class "Polygon"
# Field "sides": [1] 3
square<-octagon
# Reference class object of class "Polygon"
# Field "sides": [1] 8
square #the variable square changes
# Reference class object of class "Polygon"
# Field "sides": [1] 8
pList # but the entry in pList does now.
# [[1]] Reference class object of class "Polygon"
# Field "sides": [1] 4
# [[2]] Reference class object of class "Polygon"
# Field "sides": [1] 3
#the same is true the other way around, changing the item corresponding to triangle in the list,
#does not change the object triangle
triangle$sides #3
pList[[2]]$sides #3
pList[2]<-octagon
pList[[2]]$sides #8
triangle$sides #3
Does anyone know why this is or if there is a way around it?
If I change individual fields of the object the change DOES get propagated as shown in the code below but the actually classes I am working with are much more complicated than the simple polygon class used here so changing all of the fields inside each object is not really a solution for me.
square <- Polygon$new(sides = 4)
triangle <- Polygon$new(sides = 3)
octagon <- Polygon$new(sides = 8)
pList <-list(square,triangle)
#changing the list element changes the variable triangle
triangle$sides #3
pList[[2]]$sides#3
pList[[2]]$sides<-12
pList[[2]]$sides #12
triangle$sides #12
square <- Polygon$new(sides = 4)
triangle <- Polygon$new(sides = 3)
octagon <- Polygon$new(sides = 8)
pList <-list(square,triangle)
#changing the variable triangle changes the list element
triangle$sides #3
pList[[2]]$sides#3
triangle$sides<-12
pList[[2]]$sides #12
triangle$sides #12
List entries are values and not references/pointers. ReferenceClass objects reference (or point to) the data associated with them (i.e., the fields).
If you want to edit "class pointers" within a list without touching the list object directly, a new "PolygonPointer" class could be a workaround for you:
PolygonPointer <- setRefClass("PolygonPointer", fields = list(target = "Polygon"))
pointer1 <- PolygonPointer(target = square)
pointer2 <- PolygonPointer(target = triangle)
lst <- list(pointer1, pointer2)
pointer1$target <- octagon
The output is:
> lst
[[1]]
Reference class object of class "PolygonPointer"
Field "target":
Reference class object of class "Polygon"
Field "sides":
[1] 8
[[2]]
Reference class object of class "PolygonPointer"
Field "target":
Reference class object of class "Polygon"
Field "sides":
[1] 3
But note that such constructs are dangerous - for example, the default copy constructor does a "deep copy", also copying the objects pointed to. For example:
pointer3 <- pointer1$copy()
pointer3 <- triangle
pointer1 # still points to the octagon
You have to overwrite the copy-constructor of PolygonPointer
if you just want to copy the pointer itsself and not its referenced object.