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?
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"
.method
is overwritten, you could implement it in the virtual class with stop( "virtC$.method() must be implemented" )
. –
Nathalie field <- var
instead of field <<- var
) ... –
Bitterweed 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
© 2022 - 2024 — McMap. All rights reserved.
virtC
is caught, there appears to be no mechanism for ensuring that child classes actually implement all abstract methods inherited from the parent -- I am still able to declare classchildChar
without having implemented$.method
. Any way to correct this behaviour? – Bitterweed