Here's what does not work:
library(R6)
Foo = R6::R6Class(
'Foo',
public = list(
X = NULL,
metadata = NULL,
initialize = function(X, metadata){
self$X = X
self$metadata = metadata
},
`[` = function(selection){
subfoo = Foo$new(X = X[selection],
metadata = self$metadata)
return(subfoo)
}
)
)
Specifically, the [
method is garbage:
> X = matrix(1:8, ncol = 2)
> foo = Foo$new(X, 'blah blah')
> foo[1:2,]
Error in foo[1:2, ] : object of type 'environment' is not subsettable
The desired result is that foo[1:2,]
would be an object of class Foo
just like foo
except that its matrix foo$X
is smaller. Is there a direct way to implement this that exposes the [
operator directly to the user?
An answer is better late than never I suppose. The problem is that you are registering methods that can be called like
x$`[`(1:3)
whereas you want
x[1:3]
The following will dispatch all [
and [<-
calls (via S3) correctly for all R6 objects.
`[.R6` <- function(x, ...) x$`[`(...)
`[<-.R6` <- function(x, ...) x$`[<-`(...)
Note that you shouldn't do anything like this for the [[
methods, as these are already defined and used because R6 objects are environments.
Ideally it would be great if (
could also be overridden so that we could create functor objects (e.g. calling x(2)
), but I don't know how this could be done..
In case others are also looking for it, here is a complete working example of how to do this (based on Ian Fellows' answer):
library(R6)
Foo = R6::R6Class(
'Foo',
public = list(
x = NULL,
initialize = function(x) {
self$x = x
},
`[` = function(idx) {
self$x[idx]
},
`[<-` = function(idx, value) {
self$x[idx] <- value
invisible(self) # important!
},
length = function() {
length(self$x)
}
)
)
# set up method dispatch
`[.Foo` <- function(obj, ...) obj$`[`(...)
`[<-.Foo` <- function(obj, ...) obj$`[<-`(...)
length.Foo <- function(obj, ...) obj$length(...)
# test
foo <- Foo$new(c(1,2,3))
(n <- length(foo))
#> [1] 3
foo[1:n]
#> [1] 1 2 3
foo[2] <- 0
foo[1:n]
#> [1] 1 0 3
Created on 2020-10-09 by the reprex package (v0.3.0)
(The return value can be another Foo object, if you need it to be. I'm returning a vector for simplicity's sake)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With