Skip to content

Reference Classes copy(shallow=FALSE) unexpected behavior.

7 messages · Manuel Castejón Limas, Hadley Wickham, John Chambers

#
2011/5/10 Manuel Castej?n Limas <manuel.castejon at unileon.es>:
What sort of class is the Con class? S4 or reference?

Hadley
#
Dear Hadley,

Thank you very much for your interest in the question proposed.
The Con class is a Reference Class. P and k are from class listCon.

I provide in the following lines a little more detail in order to be able
to reproduce the case.

#Class declaration
gCon <- setRefClass("Con", fields=list(from="ANY",weight="numeric"))
gListAMORE <- setRefClass("listAMORE", fields=list(.Data="list"))
gListCon <- setRefClass("listCon", contains="listAMORE")

# Let's create a few connections
con1 <- gCon$new(from=1, weight=1.1)
con2 <- gCon$new(from=2, weight=2.2)
con3 <- gCon$new(from=3, weight=3.3)

# And a list of connections
lcon <-gListCon$new()
lcon$.Data <- list(con1, con2, con3)

# At this point, lcon contains:
lcon$.Data
[[1]]
An object of class "Con"
<environment: 0x9a1534>

[[2]]
An object of class "Con"
<environment: 0xcd7ff0>

[[3]]
An object of class "Con"
<environment: 0xdca724>

# Let's copy lcon to k
k <- lcon$copy(shallow=FALSE)

# Now k is a new object but the cons are shared with lcon!
k$.Data
[[1]]
An object of class "Con"
<environment: 0x9a1534>

[[2]]
An object of class "Con"
<environment: 0xcd7ff0>

[[3]]
An object of class "Con"
<environment: 0xdca724>


Best regards

Manuel



El 11/05/11 14:00, "Hadley Wickham" <hadley at rice.edu> escribi?:
#
Hi Manuel,

The source code for copy is short and pretty readable, so I'd
encourage you to look at it:
Class method definition for method copy()
function (shallow = FALSE)
{
    def <- .refClassDef
    value <- new(def)
    vEnv <- as.environment(value)
    selfEnv <- as.environment(.self)
    for (field in names(def at fieldClasses)) {
        if (shallow)
            assign(field, get(field, envir = selfEnv), envir = vEnv)
        else {
            current <- get(field, envir = selfEnv)
            if (is(current, "envRefClass"))
                current <- current$copy(FALSE)
            assign(field, current, envir = vEnv)
        }
    }
    value
}

The basic problem is that you have a list of reference class objects,
and currently copy does not recurse into lists.  I think this could be
fixed with

deep_copy <- function(x) {
  if (is(current, "envRefClass")) {
    x$copy()
  } else if (is.list(x))
    lapply(x, deep_copy)
  } else {
    x
  }
}

function (shallow = FALSE){
    def <- .refClassDef
    value <- new(def)
    vEnv <- as.environment(value)
    selfEnv <- as.environment(.self)
    for (field in names(def at fieldClasses)) {
        if (shallow)
            assign(field, get(field, envir = selfEnv), envir = vEnv)
        else {
            current <- get(field, envir = selfEnv)
            assign(field, deep_copy(current), envir = vEnv)
        }
    }
    value
}

Hadley

2011/5/11 Manuel Castej?n Limas <manuel.castejon at unileon.es>:

  
    
#
Good suggestion for this case.

But the general problem is tricky.  What about reference objects 
contained in attributes or slots of other objects, etc?  What is  needed 
for total copying is a switch in the low-level duplication code that 
says to copy reference objects.  It's also possible that one does NOT 
want all such objects copied.

For now, it may be that specialized copy() methods are needed for 
classes that have subsidiary reference objects inside non-reference objects.

John
On 5/11/11 6:37 AM, Hadley Wickham wrote:
#
Dear Hadley and John,

My main interest in the question was to understand what was happening.
Thank you very much for your clarifications and the piece of code.


Manuel


El 11/05/11 18:32, "John Chambers" <jmc at r-project.org> escribi?:
#
Good point.  I wonder what other languages do? And in fact, are there
any other languages that mix mutable and non-mutable objects in this
way?

Hadley