I want to create a class that is pretty much a data frame, with a couple of enhancements (extra functions, extra properties), and am wondering what the best way to do it is. The class is basically a data frame, but with some additional attributes such as the schema of that data frame (named "form" below, auto-derived, represented as a data frame, used to cast the data frame into the right types), and a couple of other things. When users use this object in other functions that do not recognize its special type, I want them to deal with the data.frame part of the object. What is the best way to do this?
The two methods I have found are both unsatisfactory; I list them and what issues I still see and am trying to solve; question is: what is the best way to do what I'm trying to do?
Method 1, use "data.frame" as "base" slot (inspired by this SO post)
setClass("formhubData", representation(form="data.frame"), contains="data.frame")
fd <- new('formhubData', data.frame(x=c(1,2)), form=data.frame(name='x', type='select one', label='X'))
This method allows me to do things like:
fd$x >> 1 2
names(fd) >> "x"
[Update: turns out the "break down" was being caused by my environment, in which I was calling setClass('formhubData', ...) repeatedly with different arguments. In a fresh R session, all of the below functions work as expected.]
But it breaks down pretty quickly:
nrow(fd) >> NULL
colnames(fd) >> NULL
Unlike the post linked above, even the simple is.data.frame
doesn't work for me
is.data.frame >> FALSE
Method 2, use "data" slot (inspired by SP)
setClass("formhubData", representation(data="data.frame", form="data.frame"))
fd <- new('formhubData', data=data.frame(x=c(1,2)), form=data.frame(name='x', type='select one', label='X'))
I lose the default definitions:
fd$x >> NULL
names(fd) >> integer(0)
But, at least I can re-define most of them (still have to learn about [, [[, etc.):
dim.formhubData <- function(x) dim(x@data)
names.formhubData <- function(x) names(x@data)
nrow(fd) >> 2
names(fd) >> "x"
However, it seems like that I can't express the fact that for any method that takes a data.frame, my class should be used as a passthrough to its @data slot. I feel the need for something like *.formhubData <- function(x, ...) *(x, ...)
rather than trying to guess all the functions that the clients of my class might use, and define them like dim.formhubData
, names.formhubData
, etc.
Are there any ways to achieve something like this?