diff --git a/NEWS.md b/NEWS.md index f882aca80..cff6ecb5b 100644 --- a/NEWS.md +++ b/NEWS.md @@ -199,6 +199,8 @@ Thanks to @sritchie73 for reporting and fixing [PR#2631](https://github.com/Rdat 38. Fixed a bug on Windows that `data.table` may break if the garbage collecting was triggered when sorting a large number of non-ASCII characters. Thanks to @shrektan for reporting and fixing [PR#2678](https://github.com/Rdatatable/data.table/pull/2678), [#2674](https://github.com/Rdatatable/data.table/issues/2674). +39. Internal aliasing of `.` to `list` was over-aggressive in applying `list` even when `.` was intended within `bquote`, [#1912](https://github.com/Rdatatable/data.table/issues/1912). Thanks @MichaelChirico for reporting/filing and @ecoRoland for suggesting and testing a fix. + #### NOTES 0. The license has been changed from GPL to MPL (Mozilla Public License). All contributors were consulted and approved. [PR#2456](https://github.com/Rdatatable/data.table/pull/2456) details the reasons for the change. diff --git a/R/data.table.R b/R/data.table.R index b5e46e5b6..ae00a238c 100644 --- a/R/data.table.R +++ b/R/data.table.R @@ -185,8 +185,12 @@ replace_dot_alias <- function(e) { # we don't just simply alias .=list because i) list is a primitive (faster to iterate) and ii) we test for use # of "list" in several places so it saves having to remember to write "." || "list" in those places if (is.call(e)) { + # . alias also used within bquote, #1912 + if (e[[1L]] == 'bquote') return(e) if (e[[1L]] == ".") e[[1L]] = quote(list) - for (i in seq_along(e)[-1L]) if (!is.null(e[[i]])) e[[i]] = replace_dot_alias(e[[i]]) + for (i in seq_along(e)[-1L]) { + if (!is.null(e[[i]]) && e[[i]] != 'bquote') e[[i]] = replace_dot_alias(e[[i]]) + } } e } diff --git a/inst/tests/tests.Rraw b/inst/tests/tests.Rraw index ef81215f1..5ad92e78c 100644 --- a/inst/tests/tests.Rraw +++ b/inst/tests/tests.Rraw @@ -11572,6 +11572,11 @@ test(1898.1, set2key(DT, a), error="deprecated. Please use setindex() instead.") test(1898.2, set2keyv(DT, "a"), error="deprecated. Please use setindexv() instead.") test(1898.3, key2(DT), error="deprecated. Please use indices() instead.") +# . within bquote shouldn't be swapped to list, #1912 +DT = data.table(x = 1:5, y = 6:10) +test(1899.1, DT[ , bquote(z == .(sum(x)))], substitute(z == 15L)) +test(1899.2, DT[ , .(.(bquote(z == .(sd(x - y)))))], + data.table(V1 = list(substitute(z == 0)))) ################################### # Add new tests above this line # diff --git a/man/data.table.Rd b/man/data.table.Rd index 9e5b585f1..50c91522c 100644 --- a/man/data.table.Rd +++ b/man/data.table.Rd @@ -78,7 +78,7 @@ data.table(..., keep.rownames=FALSE, check.names=FALSE, key=NULL, stringsAsFacto \item{j}{When \code{with=TRUE} (default), \code{j} is evaluated within the frame of the data.table; i.e., it sees column names as if they are variables. This allows to not just \emph{select} columns in \code{j}, but also \code{compute} on them e.g., \code{x[, a]} and \code{x[, sum(a)]} returns \code{x$a} and \code{sum(x$a)} as a vector respectively. \code{x[, .(a, b)]} and \code{x[, .(sa=sum(a), sb=sum(b))]} returns a two column data.table each, the first simply \emph{selecting} columns \code{a, b} and the second \emph{computing} their sums. - The expression `.()` is a \emph{shorthand} alias to \code{list()}; they both mean the same. As long as \code{j} returns a \code{list}, each element of the list becomes a column in the resulting \code{data.table}. This is the default \emph{enhanced} mode. + The expression `.()` is a \emph{shorthand} alias to \code{list()}; they both mean the same. (An exception is made for the use of \code{.()} within a call to \code{\link{bquote}}, where \code{.()} is left unchanged.) As long as \code{j} returns a \code{list}, each element of the list becomes a column in the resulting \code{data.table}. This is the default \emph{enhanced} mode. When \code{with=FALSE}, \code{j} can be a vector of column names or positions to select (as in \code{data.frame}), or a logical vector with length \code{ncol(x)} defining columns to select. Note: if a logical vector with length \code{k < ncol(x)} is passed, it will be filled to length \code{ncol(x)} with \code{FALSE}, which is different from \code{data.frame}, where the vector is recycled.