r-lib / R6

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

object 'super' not found (when using active members and clones) #119

Closed GregorDeCillia closed 7 years ago

GregorDeCillia commented 7 years ago

I currently have an issue with cloned objects. My setup looks roughtly like this

library( "R6" )

A = R6Class(
  'A',
  public = list(
    A_method = function(){}
  ),
  active = list(
    ns = function(){}
  )
)

B = R6Class(
  'B',
  inherit = A,
  public = list(
    B_method = function(){
      super$A_method()                  # 18
    }
  )
)

C = R6Class(
  'C',
  inherit = B,
  public = list(
    C_method = function(){
      super$B_method()                  # 28
    }
  )
)

C$new()$C_method()                      # NULL
B$new()$clone()$B_method()              # NULL
C$new()$clone()$C_method()              # Error in super$B_method() : object 'super' not found

It seems like B can't access the methods of its parent A via a call to super (in line # 18). The error does not occur, if the active member ns is ommited

Any help would be appreciated!

wch commented 7 years ago

This sounds like a duplicate of #108.

wch commented 7 years ago

It turns out this is actually different from #108. The problem doesn't have to do with active bindings per se, but it happens to come up in classes with active bindings, because of the way that as.list.environment sorts active bindings separately from other objects.

Here's a minimal example:

library(R6)

A <- R6Class("A",
  public = list(
    methodA = function() "A"
  ),
  active = list(
    x = function() "x"
  )
)

B <- R6Class("B",
  inherit = A,
  public = list(
    methodB = function() {
      super$methodA()
    }
  )
)

C <- R6Class("C",
  inherit = B,
  public = list(
    methodC = function() {
      super$methodB()
    }
  )
)

C1 <- C$new()
C2 <- C1$clone()
C2$methodC()
# Error in super$methodB() : object 'super' not found

The problem is in this line of code: https://github.com/wch/R6/blob/41f942af/R/clone.R#L58

It makes the assumption that all of the functions in the super object have the same enclosing environment. However, this is not true when there are two levels of inheritance. C's super object may have methods declared in B as well as some that were inherited from A. This is shown by:

lapply(C1$.__enclos_env__$super, environment)
# $x
# <environment: 0x10da95228>
# 
# $clone
# <environment: 0x10da8fce8>
# 
# $methodB
# <environment: 0x10da8fce8>
# 
# $A_method
# <environment: 0x10da95228>
GregorDeCillia commented 7 years ago

Thank you for the quick fix. 073b6f0daba8adc476df53a90d221a7df69a0ea1 solved all my issues in the minimal example as well as my actual project.