diff --git a/Functions.Rmd b/Functions.Rmd index e7e926ef9..353c437a3 100644 --- a/Functions.Rmd +++ b/Functions.Rmd @@ -1277,7 +1277,11 @@ x <- `names<-`(`*tmp*`, `[<-`(names(`*tmp*`), 2, "two")) rm(`*tmp*`) ``` -(Yes, it really does create a local variable named `*tmp*`, which is removed afterwards.) +(Yes, it really does create a local variable named `*tmp*`, which is removed afterwards.)[^subassignment] + +[^subassignment]: See [this StackOverflow answer](https://stackoverflow.com/a/10491881/946850) for an alternative explanation. At the time of writing, even [the R language definition](https://cran.r-project.org/doc/manuals/R-lang.html#Subset-assignment) isn't really specific about why it is necessary to use a temporary local variable, or how exactly complex assignment works with three or more levels. See for an example that attempts to shed light on what happens under the hood. + +Note the use of `[<-`, which is the replacement variant of a special form introduced below. ### Special forms \index{special forms} @@ -1292,6 +1296,13 @@ The subsetting operators: * `x[i]` (`` `[`(x, i) ``) * `x[[i]]` (`` `[[`(x, i) ``) +* `x$a` (`` `$`(x, "a") ``) + +The subassignment operators (a combination of the special and replacement forms): + +* `x[i] <- value` (`` x <- `[<-`(x, i, value) ``) +* `x[[i]] <- value` (`` x <- `[[<-`(x, i, value) ``) +* `x$a <- value` (`` x <- `$<-`(x, "a", value) ``) And the tools of control flow: diff --git a/Subsetting.Rmd b/Subsetting.Rmd index c68add6b4..a1b06a012 100644 --- a/Subsetting.Rmd +++ b/Subsetting.Rmd @@ -499,6 +499,8 @@ x[c(1, 2)] <- c(101, 102) x ``` +This looks like `x` is updated in place, but a copy of `x` is created via the copy-on-modify rules (see Section \@ref(copy-on-modify)) if it is bound to more than one name. Section \@ref(replacement-functions) describes the details of complex assignments of the form `x[i1][i2] <- value`. + I recommend that you should make sure that `length(value)` is the same as `length(x[i])`, and that `i` is unique. This is because, while R will recycle if needed, those rules are complex (particularly if `i` contains missing or duplicated values) and may cause problems. With lists, you can use `x[[i]] <- NULL` to remove a component. To add a literal `NULL`, use `x[i] <- list(NULL)`: