Closed jeffwong-nflx closed 4 years ago
Another simpler example
ClassA <- R6Class("ClassA",
public = list(
data = NULL,
initialize = function(data) {
self$data = data
},
foo = function() {
print("foo in A")
bar()
},
bar = function() {
print("bar in A")
}
)
)
ClassB <- R6Class("ClassB",
inherit=ClassA,
public = list(
data = NULL,
initialize = function(data) {
self$data = data
},
foo = function() {
print("foo in B")
self$bar()
},
bar = function() {
print("bar in B")
}
)
)
ClassC <- R6Class("ClassC",
inherit=ClassB,
public = list(
data = NULL,
initialize = function(data) {
self$data = data
},
foo = function() {
print("foo in C")
super$foo()
},
bar = function() {
print("bar in C")
super$bar()
}
)
)
When I invoke ClassC methods I see
x = ClassC$new(data.frame(a = 1))
x$foo()
[1] "foo in C"
[1] "foo in B"
[1] **"bar in C"** an extra step here.
[1] "bar in B"
I feel this is a common pattern, where a subclass behaves very similarly to its parent class, but just adds an extra step (print in this case). But because I have overwrote bar in the subclass, it defers to ClassC's bar, which then invokes class B's bar. However, I was hoping to see foo in C, foo in B, and then bar in B.
That's the way it's supposed to work. When you instantiate ClassC, it doesn't create three separate objects of ClassA, ClassB, and ClassC.
self
always refers to the object that was instantiated (in your case, of ClassC).
This behavior is so that you can do things like this :
library(R6)
Operator <- R6Class("Operator",
public = list(
compute = function(a, b) {
cat(paste0("The result is: ", self$op(a, b)))
},
op = function(a, b) {
stop("Not defined")
}
)
)
Multiplier <- R6Class("Multiplier",
inherit = Operator,
public = list(
op = function(a, b) {
a * b
}
)
)
multiplier <- Multiplier$new()
multiplier$compute(4, 5)
#> The result is: 20
Minimal Reproducible Example with problem below:
Each class here has methods
foo
andbar
. When I invoke ClassB methods they behave as expected:B = ClassB$new(data = data.frame(a = 1)); B$foo()
When I invoke ClassC methods, I expect to see
But somehow this triggers an infinite recursion. Using the debugger I am seeing that step 3 jumps to classB, the super, then invokes
foo
, then invokes self$bar, but self is actually pointing to the original ClassC instance, not to the classB instance (super) we jumped to. This triggers an infinite recursion.