0

When I gave class generators different names to the class itself (there are legitimate reasons for doing this), I started running into problems:

myClassGen <- setRefClass("myClass",
    methods = list(foo = function() baz())
)
myClassGen$methods(baz = function() "baz")

myObj <- myClassGen()
myObj$foo()

resulted in:

Error in myObj$foo() : could not find function "baz"

yet method baz clearly exists because I can do:

> myObj$baz
Class method definition for method baz()
function () 
"baz"
<environment: 0x000000002c60f0b8>

The above error does not occur if the generator name is changed to myClass.

If this behavior is by design, why? If this is a bug, then how can I fix this issue? Are there another hidden problems resulting from generators and classes having different names?

Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
mchen
  • 9,808
  • 17
  • 72
  • 125

1 Answers1

3

You need to specify that baz() has to be called on the class instance, so on .self :

myClassGen <- setRefClass("myClass",methods = list(foo = function() .self$baz()))
myClassGen$methods(baz = function() "baz")

myObj <- myClassGen()
myObj$foo()
# [1] "baz"

So, the problem is not related to the name of the class generator being different from the class name, because the following code doesn't work (note the missing .self):

myClass <- setRefClass("myClass", methods = list(foo = function() baz()))
myClass$methods(baz = function() "baz")

myObj <- myClass()
myObj$foo()
# Error in myObj$foo() : could not find function "baz"

Official documentation on Reference Classes is here.


EDIT (as per comment):

The documentation in the section regarding $methods(...) function states:

The new methods can refer to any currently defined method by name (including other methods supplied in this call to $methods(). Note though that previously defined methods are not re-analyzed meaning that they will not call the new method (unless it redefines an existing method of the same name).

If I understand correctly, this means that the new added method baz cannot be called by the previously defined method foo. If so, why does .self$foo() work fine ?
I'm not sure but I guess it has to do with the analysis of the methods mentioned in the text above.
Probably the methods defined through setRefClass are parsed and, if a call to another class method is found, the call is somehow explicitly linked to that class method to avoid confusion with a possibly existing function having the same name (as an oversimplification I imagine that these calls are prefixed by with .self$).
Instead, method calls to .self$something() are not modified since they are already explicit.

This seems reasonably supported by the following tests. For example if we run this code:

myClassGen <- setRefClass("myClass", methods = list(foo = function() baz(), 
                                                    baz = function() "baz"))
myObj <- myClassGen()
myObj$foo

we get:

Class method definition for method foo()
function () 
baz()
<environment: 0x000000000e490938>

 Methods used:  
    "baz"

where you can notice the last line stating that the class method baz is used by the foo method.

If we run this instead:

myClassGen <- setRefClass("myClass",methods = list(foo = function() .self$baz(), 
                                                   baz = function() "baz"))
myObj <- myClassGen()
myObj$foo

we get:

Class method definition for method foo()
function () 
.self$baz()
<environment: 0x00000000107ab5c8>

where there's no mention of the class method baz.

digEmAll
  • 56,430
  • 9
  • 115
  • 140
  • Ahh OK, thanks. So why do I not need to use `.self$baz()` if I create `foo` and `baz` in one go? Like `myClass <- setRefClass("myClass", methods = list(foo = function() baz(), baz = function() "baz"))`. Seems a little inconsistent in determining when `.self` is required. – mchen Jan 17 '14 at 08:44
  • Actually I don't know, probably it has something to do with the enclosing environments... anyway, I suggest to always use .self when you refer to a method of the current instance, to avoid confusion with a possibly existing function having the same name... – digEmAll Jan 17 '14 at 09:34
  • @MiloChen: edited the question wih some considerations about your comment ;) – digEmAll Jan 22 '14 at 08:45