"Skipping" Inheritance levels in R6

I am using r6 for a large project. I would really benefit from the ability to have a class use functionality from a "grandparent" class while skipping the "parent" class entirely. I believe that this is possible in C++ (which was my first exposure to OOP). I am unclear if this is possible in r6 as well.

Here is an example that demonstrates my issue. Consider this class hierarchy:

library(R6)

A <- R6Class("A",
  public = list(
    fun = function() {
      print("In A$fun()")
    }
  )
)


B <- R6Class("B",
  inherit = A,
  public = list(
    fun = function() {
      print("In B$fun()")
      super$fun()
    }
  )
)

C <- R6Class("C",
   inherit = B,
   public = list(
     fun = function() {
       print("In C$fun()")
       super$fun()
     }
   )
)

If we create a new object C and run fun() on it, we run A$fun() as well as B$fun():

> obj <- C$new()

> obj$fun()
[1] "In C$fun()"
[1] "In B$fun()"
[1] "In A$fun()"

I would like to write code that generates this output instead:

> obj <- C$new()

> obj$fun()
[1] "In C$fun()"
[1] "In A$fun()"

That is, I want C to be able to execute code in A$fun() while ignoring / skipping the code in B$fun().

From memory, I think that in C++ I could do this by writing A::fun() while in C. But the syntactic equivalent in R (A$fun()) generates an error.

Colin Fay has a blog post where he describes a workaround for this exact problem (link). However, I am unclear if that is considered the authoritative / accepted solution to this problem.

cc @winston who I believe created r6.

It is possible to do this, but it is a bit of a hack:

C <- R6Class("C",
   inherit = B,
   public = list(
     fun = function() {
       print("In C$fun()")
       super$.__enclos_env__$super$fun()
     }
   )
)
1 Like

Thanks @winston !

Just to confirm, you are unlikely to add support for this within the r6 package itself, right? When I look at the NEWS and archive for r6 on CRAN (link) it looks like the project is pretty mature, and you're not really looking to add functionality to it.

The example uses some of the internal R6 API, but it's very, very unlikely that R6 will change in a way that will cause that to break. I don't think it would be possible to change that aspect of R6 without breaking many, many downstream packages.

And you are correct that an official version of this feature is unlikely to be added to R6.

(Please note that I just updated the example with a slightly better solution than the one I originally wrote.)

2 Likes

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.