Mikael Jagan
2024-Apr-27 14:53 UTC
[Rd] Should c(..., recursive = TRUE) and unlist(x, recursive = TRUE) recurse into expression vectors?
Reading the body of function 'AnswerType' in bind.c, called from 'do_c' and 'do_unlist', I notice that EXPRSXP and VECSXP are handled identically in the recurse = TRUE case. A corollary is that c(recursive = TRUE) and unlist(recursive = TRUE) treat expression vectors like expression(a, b) as lists of symbols and calls. And since they treat symbols and calls as lists of length 1, we see: > x <- expression(a, b); y <- expression(c, d) > c(x, y) expression(a, b, c, d) > c(x, y, recursive = TRUE) [[1]] a [[2]] b [[3]] c [[4]] d My expectation based on the documentation in help("c") and help("unlist") is that those functions would recurse into lists and pairlists, but _not_ into expression vectors. recursive: logical. If 'recursive = TRUE', the function recursively descends through lists (and pairlists) combining all their elements into a vector. recursive: logical. Should unlisting be applied to list components of 'x'? My feeling is that either: (1) the behaviour should change, so that both calls to 'c' above give the result of type "expression". (2) the documentation should change to say that expression vectors are handled as lists in the recursive case. Option (2) won't break anything but is a bit awkward because it means that a type "higher" in the documented hierarchy (... < list < expression) is coerced to a lower type. I'll add here that, confusingly, help("expression") says: "an object of mode 'expression' is a list". I understand the author's intent (lists and expression vectors differ only in the 'type' field of the SEXP header) but I wonder if substituting "list" with "generic vector" there would cause less confusion ... ? Mikael
Mikael Jagan
2024-Apr-27 15:20 UTC
[Rd] Should c(..., recursive = TRUE) and unlist(x, recursive = TRUE) recurse into expression vectors?
On 2024-04-27 10:53 am, Mikael Jagan wrote:> Reading the body of function 'AnswerType' in bind.c, called from 'do_c' > and 'do_unlist', I notice that EXPRSXP and VECSXP are handled identically > in the recurse = TRUE case. > > A corollary is that c(recursive = TRUE) and unlist(recursive = TRUE) > treat expression vectors like expression(a, b) as lists of symbols and > calls. And since they treat symbols and calls as lists of length 1, we > see: > > > x <- expression(a, b); y <- expression(c, d) > > c(x, y) > expression(a, b, c, d) > > c(x, y, recursive = TRUE) > [[1]] > a > > [[2]] > b > > [[3]] > c > > [[4]] > d > > My expectation based on the documentation in help("c") and help("unlist") > is that those functions would recurse into lists and pairlists, but _not_ > into expression vectors. > > recursive: logical. If 'recursive = TRUE', the function recursively > descends through lists (and pairlists) combining all their > elements into a vector. > > recursive: logical. Should unlisting be applied to list components of > 'x'? > > My feeling is that either: > > (1) the behaviour should change, so that both calls to 'c' above give > the result of type "expression". > (2) the documentation should change to say that expression vectors are > handled as lists in the recursive case. > > Option (2) won't break anything but is a bit awkward because it means > that a type "higher" in the documented hierarchy (... < list < expression) > is coerced to a lower type. >Er - this last comment about Option (2) being awkward can be ignored. The expression vector is not itself coerced to a list. Rather, its non-vector components are treated as lists of length 1. And that's well-documented. If anything, Option (1) is awkward as it would treat two types of generic vectors, list and expression, asymmetrically ... I can submit a patch implementing Option (2) in a few days to allow for comments if any. Mikael> I'll add here that, confusingly, help("expression") says: "an object of > mode 'expression' is a list". I understand the author's intent (lists and > expression vectors differ only in the 'type' field of the SEXP header) but > I wonder if substituting "list" with "generic vector" there would cause > less confusion ... ? > > Mikael