Search code examples
roopinheritancemultiple-inheritancereference-class

R Reference Class multiple inheritance: how to call method in a specific parent class?


I have a reference class Child which inherits from parents SuperA and SuperB. When in the initialize method of Child, I would like to invoke the initialize methods of both SuperA and SuperB in turn.

Thus, for instance, I have:

SuperA <- setRefClass("SuperA",
    fields = list(a = "ANY"),
    methods = list(
        initialize = function(a) {
            print(a)
            initFields(a = a)
        }
    )
)

SuperB <- setRefClass("SuperB",
    fields = list(b = "ANY"),
    methods = list(
        initialize = function(b) {
            print(b)
            initFields(b = b)
        }
    )
)

Child <- setRefClass("Child",
    contains = c("SuperA", "SuperB"),
    methods = list(
        initialize = function(a, b) {
            # attempt to invoke parent constructors one by one:
            SuperA$callSuper(a)
            SuperB$callSuper(b)
        }
    )
)

Child(1, 2)   # want values 1 and 2 to be printed during construction of superclasses

However all I get is:

Error in print(a) : argument "a" is missing, with no default 

So does anyone have any ideas on how to invoke a method belonging to a particular parent?


Solution

  • I'm not a heavy reference class user, but in S4 (on which reference classes are based) the best approach is often to avoid defining initialize methods (which have a complicated contract, both 'initialize' and 'copy' of named and unnamed arguments), to treat the constructor returned by setClass() as for internal use only, and to provide a user-facing constructor. Thus

    .SuperA <- setRefClass("SuperA", fields = list(a = "ANY"))
    
    .SuperB <- setRefClass("SuperB", fields = list(b = "ANY"))
    
    .Child <- setRefClass("Child", contains = c("SuperA", "SuperB"))
    
    Child <- function(a, b)
        ## any coercion, then...
        .Child(a=a, b=b)
    

    The result is

    > Child(a=1, b=2)
    Reference class object of class "Child"
    Field "b":
    [1] 2
    Field "a":
    [1] 1
    

    From ?ReferenceClasses, the method $export(Class) coerces the object to an instance of 'Class', so

    .SuperA <- setRefClass("SuperA", fields = list(a = "ANY"),
        methods=list(foo=function() .self$a))
    
    .SuperB <- setRefClass("SuperB", fields = list(b = "ANY"),
        methods=list(foo=function() .self$b))
    
    .Child <- setRefClass("Child", contains = c("SuperA", "SuperB"),
        methods=list(foo=function() {
            c(export("SuperA")$foo(), export("SuperB")$foo())
        }))
    
    Child <- function(a, b)
        .Child(a=a, b=b)
    

    Leads to

    > Child(a=1, b=2)$foo()
    [1] 1 2