I am trying to debug the constructor of an R6 parent class via invoking the child class.
Here is the code
library(R6)
parent <- R6Class(
"parent",
public=list(
y=data.table(),
initialize=function(){
cat("hello","\n")
self$y <- data.table(a=rep(1,5),b=rep("a",5))
for(i in 1:5){
cat("bla \n")
}
}
)
)
child <- R6Class(
"child",
inherit=parent,
public=list(
initialize=function(){
super$initialize();
}
)
)
parent$debug("initialize")
child$debug("initialize")
x <- child$new() ##debugging of parent consturctor doesn't work
y <- parent$new() ##debugging of parent consturctor works
So far, when constructing the child the debugger does not move through the parent constructor. The parent constructor code is executed as if debugging is switched off.
Any idea how to step through the parent constructor code without invoking the parent directly?
R Version: 4.3.2 R6 Version: 2.5.1 OS: Linux, kernel 6.7 R environment: emacs ess
debug()is for closures and environmentsLet's look at a standard function both before and after it is being debugged.
As R Internals sets out, R objects have a header defined in C which defines the type of object plus some other information, including the debug bit:
Note that once
fis being debugged, the above output of.Internal(inspect(f))indicates it has the debug bit (DBG) set.The problem is how this works with R6 classes.
parentis not an instance of an object, but rather is a class, i.e. a factory for creating instances of objects of typeparent. This means thatparent$initialize()is not a function.So we cannot technically debug the initialize method of the parent class, but only the initialize method of an instantiated object of the parent class:
Now you might think that you can debug
parent$new()because it appears to be a function:However, the only benefit to it being a closure is that
isdebugged()will not raise an error, but instead tell you that R will not allow you to set the debug flag.Why debug works when you instantiate an object of type
parentIf you run
parent$debug("initialize")then any the initialize method of any object of classparentwill be debugged:This means that when you create
xyou will enter the debug browser because the initialize method is called onx, rather than becauseparent$initializeis debugged. However, that's no use to you here as you are creating an object of typechild.How to
debug()thesuperclassHowever, it is possible to address this from within the debug browser. That is because
superis not seen as a class, but in fact an environment and the initialize method is a function:We can debug environments and functions. So once we're in the browser, we can enter the debug instruction relating to
superrather thanparent. So call (the debugged)child$new()and then before you press enter in the browser:You'll see that this lets you step through into the next level,
Browse[3]:If you are going to be doing a lot of debugging and don't want to enter this every time, you could amend your
initialize()function for the child class to include adebug_parentflag:You could then call this as follows:
You will want to remember to take this out when you've finished, but it avoids the need to ask the browser to debug the parent every time you call the child.