简体   繁体   中英

How can I define a class in R for storing user defined functions?

I come from using C#, PHP, javascript, etc. To me, it makes sense to be able to do something like:

class SomeClass {
    public function myFunction($var) {
        echo $var;
    }
}

$myClass = new SomeClass();

$myClass->myFunction('test');

I want to do this with R - is there something equivalent to this to help avoid naming conflicts? every time I load a package it tells me there are functions with common names in other packages and I just want to do avoid this.

R reference classes have that 'feel'

.SomeClass <- setRefClass("SomeClass",
    methods = list(
      myFunction = function(var) {
          message(var)
      }))

and then

> myClass <- .SomeClass()
> myClass$myFunction('test')
test

In many cases a different solution is to use the S3 or S4 object system, and to implement methods on existing or newly created generics. The S4 version might look like

.A <- setClass("A",
  representation=representation(
    name="character",
    age="integer"))

A <- function(name=character(), age=integer(), ...)
    ## constructor: type check / coercion, then create
    .A(name=as.character(name), age=as.integer(age), ...)

setMethod("length", "A", function(x) {
    ## getGeneric("length") to discover existing generic
    length(x@name)
})

setMethod("show", "A", function(object) {
    ## how to display the object -- existing generic 'show'
    cat("class:", class(object), "\n")
    cat("length:", length(object), "\n")
    cat("name:", paste(sQuote(object@name), collapse=", "), "\n")
    cat("age:", paste(object@age, collapse=", "), "\n")
})

setGeneric("toupper")                   # no existing generic; create one

setMethod("toupper", "A", function(x) {
    ## use default 'initialize' method as copy constructor; return a
    ## new (updated) instance
    initialize(x, name=toupper(x@name))
})

and in use:

> a <- A(c("fred", "ginger"), c(88, 83))
> a
class: A 
length: 2 
name: 'fred', 'ginger' 
age: 88, 83 
> toupper(a)
class: A 
length: 2 
name: 'FRED', 'GINGER' 
age: 88, 83 

And the S3 version (note that there is no class definition, other than in the constructor):

B <- function(name, age) {
    obj <- list(name=as.character(name), age=as.integer(age))
    class(obj) <- "B"
    obj
}

length.B <- function(x)
    ## 'length' is an S3 generic, but hard to know
    length(x$name)

print.B <- function(x, ...) {
    ## 'print' at the command line contains body UseMethod --
    ## signalling an existing S3 generic
    cat("class:", class(x), "\n")
    cat("length:", length(x), "\n")
    cat("name:", paste(sQuote(x$name), collapse=", "), "\n")
    cat("age:", paste(x$age, collapse=", "), "\n")
}

toupper.default <- base::toupper

toupper <- function(x, ...)
    UseMethod("toupper")

toupper.B <- function(x, ...) {
    x$name <- toupper(x$name)
    x
}

Perhaps both S3 and S4 implementations of new generics on existing functions cause a message about 'masking' when the new generic is exported from your package, so that doesn't really help with your question. In the example above the functionality of toupper() available in the base package is retained even if your generic masks the original definition; problems arise in S4 when package A defines a generic toupper, and package B defines a generic toupper, so that the user needs to disambiguate A::toupper() to get the correct table of methods.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM