Got some progress on this, but still not sure how to continue. First, a much more simple script reproducing the behaviour that confuses me: foo <- function(x, ...) structure(x, class = 'foo') `[.foo` <- function(x, i, ..., drop = TRUE) { print(sys.call()) print(match.call()) foo(NextMethod()) # x[] should return an object of class foo } `[<-.foo` <- function(x, i, ..., value) { print(sys.call()) print(match.call()) x[i, ..., drop = FALSE] # imagine that we need to perform some checks on the # subset of x that we're about to replace NextMethod() } x <- foo(42) x[] # this works x[] <- 1 # this doesn't Now, the crucial difference between the x[] and x[] <- 1 calls is that in the former case, the `i` argument isn't even specified: x[] # `[.foo`(x, ) # `[.foo`(x = x) # [1] 42 # attr(,"class") # [1] "foo" While in the latter case, `i` is specified in the x[] call (but missing): x[] <- 1 # `[<-.foo`(`*tmp*`, , value = 1) # `[<-.foo`(x = `*tmp*`, value = 1) # x[i, ..., drop = FALSE] # `[.foo`(x = x, i = i, drop = FALSE) Error in NextMethod() : argument "i" is missing, with no default What's the best way to forward the arguments from [<-.class methods to the [.class methods in order to handle cases like x[] properly? -- Best regards, Ivan
I haven't followed this thread, so this may be stupid, but have you looked at the do.call(`[`,...) idiom? Something like: x <- array(1:8, c(2,2,2))> x, , 1 [,1] [,2] [1,] 1 3 [2,] 2 4 , , 2 [,1] [,2] [1,] 5 7 [2,] 6 8> l <- as.list(rep(TRUE, 2)) > do.call(`[`, c(list(x), l, list(1, drop = TRUE)))[,1] [,2] [1,] 1 3 [2,] 2 4 Feel free to ignore without comment if this is unhelpful. Bert Gunter Bert Gunter "The trouble with having an open mind is that people keep coming along and sticking things into it." -- Opus (aka Berkeley Breathed in his "Bloom County" comic strip ) On Wed, Dec 8, 2021 at 5:52 AM Ivan Krylov <krylov.r00t at gmail.com> wrote:> > Got some progress on this, but still not sure how to continue. First, a > much more simple script reproducing the behaviour that confuses me: > > foo <- function(x, ...) structure(x, class = 'foo') > `[.foo` <- function(x, i, ..., drop = TRUE) { > print(sys.call()) > print(match.call()) > foo(NextMethod()) # x[] should return an object of class foo > } > `[<-.foo` <- function(x, i, ..., value) { > print(sys.call()) > print(match.call()) > x[i, ..., drop = FALSE] > # imagine that we need to perform some checks on the > # subset of x that we're about to replace > NextMethod() > } > > x <- foo(42) > x[] # this works > x[] <- 1 # this doesn't > > Now, the crucial difference between the x[] and x[] <- 1 calls is that > in the former case, the `i` argument isn't even specified: > > x[] > # `[.foo`(x, ) > # `[.foo`(x = x) > # [1] 42 > # attr(,"class") > # [1] "foo" > > While in the latter case, `i` is specified in the x[] call (but > missing): > > x[] <- 1 > # `[<-.foo`(`*tmp*`, , value = 1) > # `[<-.foo`(x = `*tmp*`, value = 1) > # x[i, ..., drop = FALSE] > # `[.foo`(x = x, i = i, drop = FALSE) > Error in NextMethod() : argument "i" is missing, with no default > > What's the best way to forward the arguments from [<-.class methods to > the [.class methods in order to handle cases like x[] properly? > > -- > Best regards, > Ivan > > ______________________________________________ > R-help at r-project.org mailing list -- To UNSUBSCRIBE and more, see > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.
>>>>> Ivan Krylov >>>>> on Wed, 8 Dec 2021 16:52:00 +0300 writes:I have always learnt a lot about programming when reading other people's code .. notably if those people new what they are doing. In this case, studying R-core's `[.data.frame` and `[<-.data.frame` {or for S4 methods, the 'Matrix' or 'Rmpfr' packages} should show you a lot. What you should take from there: Do work with *both* missing(drop) and nargs() (and more) in order to distinguish m[i] from m[i,] etc Best, Martin > Got some progress on this, but still not sure how to continue. First, a > much more simple script reproducing the behaviour that confuses me:> foo <- function(x, ...) structure(x, class = 'foo') > `[.foo` <- function(x, i, ..., drop = TRUE) { > print(sys.call()) > print(match.call()) > foo(NextMethod()) # x[] should return an object of class foo > } > `[<-.foo` <- function(x, i, ..., value) { > print(sys.call()) > print(match.call()) > x[i, ..., drop = FALSE] > # imagine that we need to perform some checks on the > # subset of x that we're about to replace > NextMethod() > } > > x <- foo(42) > x[] # this works > x[] <- 1 # this doesn't > > Now, the crucial difference between the x[] and x[] <- 1 calls is that > in the former case, the `i` argument isn't even specified: > > x[] > # `[.foo`(x, ) > # `[.foo`(x = x) > # [1] 42 > # attr(,"class") > # [1] "foo" > > While in the latter case, `i` is specified in the x[] call (but > missing): > > x[] <- 1 > # `[<-.foo`(`*tmp*`, , value = 1) > # `[<-.foo`(x = `*tmp*`, value = 1) > # x[i, ..., drop = FALSE] > # `[.foo`(x = x, i = i, drop = FALSE) > Error in NextMethod() : argument "i" is missing, with no default > > What's the best way to forward the arguments from [<-.class methods to > the [.class methods in order to handle cases like x[] properly? > > -- > Best regards, > Ivan > > ______________________________________________