4

I have an S3 object in R, something like:

myObject <- list(
    someParameter1 = 4,
    someList = 1:10
)
class(myObject) <- "myClass"

I created an extraction method for this class:

"[.myClass" <- function(x, i) {
    x$someList[i] * x$someParameter1
}
myObject[5]
# 20

Now I want to create an assignment method (from ?Extract I understand that's called a subassignment), so that I can write:

myObject[5] <- 250
myObject[5]
# 1000

I first naively tried to write this as

"[<-.myClass" <- function(x, i, value) {
    x$someList[i] <- value
}

but for some reason this replaces myObject with value. I suspect I must modify x and then assign("someName", x, pos=somewhere), but how can I reliably determine someName and somewhere?

Or is there an different way to do this?

Calimo
  • 7,510
  • 4
  • 39
  • 61

2 Answers2

5

You need to return x:

"[<-.myClass" <- function(x, i, value) {
    x$someList[i] <- value
    x
}

If you don't use return in your function call, the value of the last evaluated expression will be returned. In the case of your original function, the value of the expression is value. To illustrate:

"[<-.myClass" <- function(x, i, value) {
    print(x$someList[i] <- value)
    x
}
myObject[5] <- 250
# [1] 250 
Joshua Ulrich
  • 173,410
  • 32
  • 338
  • 418
  • correct, would you mind explaining why I need to return x because I don't get it... – Calimo Oct 31 '13 at 16:14
  • That's what I saw as well, but why does this assignment replace the whole object? Is the assignment somehow propagated downwards or something like this? – Calimo Oct 31 '13 at 16:23
  • 1
    @Calimo: because `<-` is recursive. See [this answer](http://stackoverflow.com/a/10491881/271616). – Joshua Ulrich Oct 31 '13 at 16:27
  • Ok, so `myObject[5] <- 250` is in fact `myObject <- \`[<-.myClass\`(myObject, 5, 250)`. Now it's obvious, thanks! – Calimo Oct 31 '13 at 16:43
2

To complement Joshua Ulrich's excellent answer, the reason you need to return x is because R translates

myObject[5] <- 250

into

myObject <- `[<-.myClass`(myObject, 5, 250)

It is immediately clear why you need to return x (which was myObject outside the function): the return value is assigned to myObject.

Calimo
  • 7,510
  • 4
  • 39
  • 61