r-lib / R6

Encapsulated object-oriented programming for R
https://R6.r-lib.org
Other
407 stars 56 forks source link

Deep cloning with C++ pointers involved #86

Closed Enchufa2 closed 8 years ago

Enchufa2 commented 8 years ago

I have a very specific problem because of the way deep cloning is performed. Maybe you could shed some light, because I don't see any elegant way to do what I'm trying. I'll try to explain myself as concise as possible.

I have an R6 class which encapsulates a C++ double-linked list. One member holds the head of the chain and other member holds the tail. I need to clone the chain, link by link (I already implemented this C++ part), and update head and tail in my cloned R6 class.

My first approach has been to write a deep_clone() member which, if name == head, clones the chain and returns the new head, but I have no way to update the tail with this approach. The same applies the other way around if I try to do the same from the tail.

So the question is: is there any way to perform some post-cloning tasks? Or am I missing something? Thanks in advance.

wch commented 8 years ago

That does sound a little tricky. There's no built-in way of doing post-cloning tasks. Have you considered writing your own copy() method, and skipping R6's built-in cloning mechanism entirely?

Enchufa2 commented 8 years ago

Yeap, that's my fallback. But I would like to maintain the method clone, as it's the standard way to do that in R6, without rewriting all the bolerplate needed to clone all the other members of my class.

I suppose clone is not inherited from a base class, so there is no way to overload clone and call the parent call from inside, isn't it?

wch commented 8 years ago

The cloning function does some special stuff to the object and is fairly complex, so it's not possible to override it.

Maybe your copy method could first call clone and then do the post-cloning fixing of tail?

Enchufa2 commented 8 years ago

Indeed, but I would like it to be transparent for the user of my package, so that he/she can call clone. For instance, maybe something like the following may work:

# Inside my package
MyClass <- R6Class("MyClass",
  public = list(
    copy = function() {
      self$clone_backup()
      # post-cloning stuff
    }
))

MyClass$clone_backup <- MyClass$clone
MyClass$clone <- MyClass$copy

# User
myclass <- MyClass$new()
another <- myclass$clone()
Enchufa2 commented 8 years ago

Well... this hack seems to work, but maybe I'm breaking something else along the path:

MyClass <- R6Class("MyClass",
  private = list(
    head = NULL, tail = NULL,
    # dummy function
    clone2 = function(){},
    # this one will do the work
    copy = function(deep = FALSE) {
      # call the dummy function
      new <- private$clone2(deep)
      # clone the chain here
      new$.__enclos_env__$private$head <- first
      new$.__enclos_env__$private$tail <- last
      new
    }
))
# backup the original cloning method in the dummy function
MyClass$private_methods$clone2 <- MyClass$public_methods$clone
# overwrite the cloning method
MyClass$public_methods$clone <- MyClass$private_methods$copy