Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a virtual reference class in R?

I can't find much on virtual/abstract classes in help(ReferenceClasses) - can anyone provide a basic example in creating one? Moreover, how can I specify a virtual method and enforce that child classes must implement it?

like image 935
mchen Avatar asked Jan 15 '14 16:01

mchen


2 Answers

Reference classes are S4 classes. SO maybe you should see the help of setClass and Classes:

Here a dummy example:

# virtual Base Class
setRefClass( 
  Class="virtC", 
  fields=list( 
    .elt="ANY" 
  ),
  methods = list(
    .method = function(){
      print("Base virtual method is called")
    }
  ), 
  contains=c("VIRTUAL") 
) 
   
## child 1
## field as numeric and base .method is used
setRefClass( 
  Class="childNum", 
  fields=list( 
    .elt="numeric" 
  ), 
  contains=c("virtC")  
)


## child 2 
## field is char and .method is overwritten
setRefClass( 
  Class="childChar", 
  fields=list( 
    .elt="character" 
  ), 
  methods = list(
    .method = function(){print('child method is called')}
  ), 
  contains=c("virtC") 
) 
##  new('virtA')          ## thros an error can't isntantiate it
a = new("childChar",.elt="a")
b =   new("childNum",.elt=1)

b$.method()
[1] "Base virtual method is called"

a$.method()
[1] "child method is called"
like image 128
agstudy Avatar answered Oct 20 '22 05:10

agstudy


This is an approach I am thinking of taking to catch unimplemented methods from inherited VIRTUAL "interfaces". It doesn't catch an incorrect implementation statically, but it does error if you try to instantiate an object that doesn't implement all of an interfaces methods. Rather than wait for a runtime error when invoking an unimplemented function, this bombs as soon as you try to create an object.

Helper Functions

Helper function to search the inheritance tree for interfaces. This is too basic right now. What I need to do is crawl the tree and check for parents that inherit the Interface class themselves...

.get_interface_methods <- function(.self) {

  ## Get the environment of the class being instantiated
  env <- attributes(.self$.refClassDef)$refMethods

  ## get original interface methods
  supers <- selectSuperClasses(class(.self))
  methods <- unlist(lapply(supers, function(x) getRefClass(x)$methods()))

  ## check the body is NOT null in the concrete class environment
  funs <- Filter(is.function, lapply(methods, get, envir=env))
  null_fun_body <- vapply(Map(body, funs), is.null, T)

  ## return names of functions not implemented
  vapply(funs[null_fun_body], attr, "", which="name")
}

Another helper function that is called when instantiating an object that contains one or more interfaces.

.validate_interface <- function(.self) {

  methods <- get_interface_methods(.self)

  ## stop the world and print out the un-implemented methods
  if (length(methods) > 0L) {
    stop("Must implement interface methods: ", paste(methods, collapse = ", "))
  }
}

The Classes

The Interface class simply calls the validate function during initialization. A class that inherits from Interface can register interface methods using any function that has a NULL body. I created a simple helper for that.

setRefClass(
  "Interface",
  methods = list(
  initialize = function() {
    validate(.self)
  }), contains="VIRTUAL")

InterfaceMethod <- function() NULL

Interfaces

Here I create two interfaces with dummy methods that have NULL bodies.

## Create an interface to be implemented
setRefClass(
  "ITest1",
  contains=c("VIRTUAL", "Interface"),
  methods = list(
    foo = InterfaceMethod,
    bar = InterfaceMethod,
    baz = InterfaceMethod
))

## create a second interface
setRefClass(
  "ITest2",
  contains=c("VIRTUAL", "Interface"),
  methods = list(
    spam = InterfaceMethod,
    ham  = InterfaceMethod
  ))

Instantiating an Object

Finally, I create a class definition that is not virtual and that inherits both of my defined interfaces. In the definition, I implement two of the interface functions foo & baz but do not implement bar, spam, or ham:

Obj <- setRefClass(
  "Obj",
  contains = c("ITest1", "ITest2"),
  methods = list(
    foo = function() "Implemented!",
    baz = function() "Implemented!"
))

When I try to instantiate this object, I get an error.

> x <- Obj$new()
 Error in validate(.self) : 
  Must implement interface methods: bar, ham, spam
like image 23
Zelazny7 Avatar answered Oct 20 '22 07:10

Zelazny7