2

Problem:

I wish to create a Reference Class that extends a data.table.

The motivation being

  1. Want a data.table with custom methods and mutable fields
  2. Still want all existing syntax (such as indexing, subset, merge etc) to work as expected

Problem is I have so far failed.

Attempts:

I tried:

MyDataTable <- setRefClass("MyDataTable",
    methods = list(
        clearCell = function(i, j) {        # A trivial custom method - sets a cell to NA
            .self[i, (j) := NA]
        }
    ),
    contains = "data.table"
)

MyDataTable(a = 1:26, b = letters)$clearCell(1, 1)

But got the error:

Error in envRefSetField(.Object, field, classDef, selfEnv, elements[[field]]) : 
  ‘a’ is not a field in class “MyDataTable”

However, I was expecting something like:

     a b
 1: NA a
 2:  2 b
 3:  3 c
 4:  4 d
 5:  5 e
 6:  ... etc etc 

What's going wrong?

mchen
  • 9,808
  • 17
  • 72
  • 125
  • I'm curious about the motivation - can please give an example problem? – eddi Aug 05 '14 at 15:23
  • @eddi - many examples of why one might want to extend the capabilities of a `data.table`. For instance, consider a `data.table` that is an abstraction of a database table. That is, I can write to the database table simply via `MyTable[id == 4, field := "a"]` *and* also have the in-memory table within my R session updated. For this to work, such an extended `data.table` would need to keep track of additional variables such as (database connection, name of database table it is linked to etc.) which would be best stored as reference class fields. – mchen Aug 05 '14 at 15:39

1 Answers1

1

You're not initializing your reference class object correctly. I don't know how contains is supposed to work, but a simple field works:

MyDataTable <- setRefClass("MyDataTable",
                   fields  = list(.dt = 'data.table'),
                   methods = list(initialize = function(...){
                                    .self$.dt <- data.table(...)
                                  },
                                  clearCell  = function(i, j){
                                    .self$.dt[i, (j) := NA]
                                  },
                                  bracket    = function(...){
                                    .self$.dt[...]
                                  }
                                  ))

MyDataTable(a = 1:5, b = letters[1:5])$clearCell(1,1)
#    a b
#1: NA a
#2:  2 b
#3:  3 c
#4:  4 d
#5:  5 e

MyDataTable(a = 1:5, b = letters[1:5])$bracket(b == 'c', a := 10)
#    a b
#1:  1 a
#2:  2 b
#3: 10 c
#4:  4 d
#5:  5 e
eddi
  • 49,088
  • 6
  • 104
  • 155
  • Thanks @eddi, but my second request in the question was: `still want all existing syntax (such as indexing, subset, merge etc) to work as expected`. However, with your setup, using the usual indexing like `MyDataTable(a = 1:5)[, a := a + 1]` fails. – mchen Aug 05 '14 at 16:37
  • I'm pretty sure you can't do that. You could add a different function that would call `[.data.table` though - see edit. – eddi Aug 05 '14 at 17:11