Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ export(fctr)
S3method("[", data.table)
S3method("[<-", data.table)
# S3method("[[", data.table)
# S3method("[[<-", data.table)
S3method("[[<-", data.table)
S3method("$<-", data.table)
S3method(print, data.table)
S3method(as.data.table, data.table)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -346,6 +346,8 @@ See [#2611](https://github.com/Rdatatable/data.table/issues/2611) for details. T

23. `fread()` auto-detects separators for single-column files consisting solely of quoted values (e.g. `"this_that"\n"2025-01-01 00:00:01"`), [#7366](https://github.com/Rdatatable/data.table/issues/7366). Thanks @arunsrinivasan for the report and @ben-schwen for the fix.

24. Assigning via `[[<-` now changes data.tables by reference, so forms like `DT[["col"]] = value` or `DT[[1, "col"]] = value` keep over-allocation intact instead of falling back to the data.frame method, [#6734](https://github.com/Rdatatable/data.table/issues/6734). Thanks @mb706 for the report and @ben-schwen for the implementation.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we emphasize not doing this? 😄

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we decide to do so than we should also advocate more on not using $, but I guess thats the charm of data.table. Your code, that you have written before simply works.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess the question is whether cedta() is sufficient to prevent cases where [[<- winds up being invoked by reference where the author intended it to use "normal" R copy-on-write behavior. $<-.data.table does copy(x).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True, but in any case $<- and [[<- shouldn't diverge in their behavior, right?


### NOTES

1. The following in-progress deprecations have proceeded:
Expand Down
6 changes: 6 additions & 0 deletions R/as.data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,12 @@ as.data.table.list = function(x,
rownames_ = NULL
check_rownames = !isFALSE(keep.rownames)

# conversion must happen after capturing names
if (is.data.table(x)) {
# operate on plain list to avoid [[<-.data.table dispatch
x = as.list(x)
}

for (i in seq_len(n)) {
xi = x[[i]]
if (is.null(xi)) next # eachncol already initialized to 0 by integer() above
Expand Down
17 changes: 17 additions & 0 deletions R/data.table.R
Original file line number Diff line number Diff line change
Expand Up @@ -2308,6 +2308,23 @@ tail.data.table = function(x, n=6L, ...) {
set(x,j=name,value=value) # important i is missing here
}

"[[<-.data.table" = function(x, i, j, value) {
n = nargs()
if (!cedta()) {
# nocov start
ans = if (n<4L) `[<-.data.frame`(x, i, value=value)
else `[<-.data.frame`(x, i, j, value)
return(setalloccol(ans)) # over-allocate (again)
# nocov end
}
x = copy(x)
if (n<4L) {
set(x, j=i, value=value)
} else {
set(x, i, j, value)
}
}

as.data.frame.data.table = function(x, row.names = NULL, ...)
{
ans = setDF(copy(x), rownames = row.names) # issue #5319
Expand Down
16 changes: 13 additions & 3 deletions inst/tests/tests.Rraw
Original file line number Diff line number Diff line change
Expand Up @@ -1405,10 +1405,18 @@ test(437.2, truelength(DT), 2044L)
DT = data.table(a=1:3,b=4:6)
tl = truelength(DT)
DT$foo = 7L
test(438, truelength(DT), tl)
test(438.1, truelength(DT), tl)
DT[,"bar"] = 8L
test(439, truelength(DT), tl+2L)
test(440, DT, data.table(a=1:3,b=4:6,foo=7L,bar=8L))
test(438.2, truelength(DT), tl+2L)
# also allow DT[[...]]= syntax #6734
DT[["baz"]] = 1L
test(438.3, truelength(DT), tl+2L)
test(438.4, DT$baz, c(1L,1L,1L))
DT[[5]] = 9L
test(438.5, truelength(DT), tl+3L)
DT[[1,"qux"]] = 10L
test(438.6, truelength(DT), tl+3L)
test(438.7, DT, data.table(a=1:3,b=4:6,foo=7L,bar=8L,baz=9L,qux=c(10L,NA_integer_,NA_integer_)))

# Test rbind works by colname now, for consistency with base, FR#1634
DT = data.table(a=1:3,b=4:6)
Expand Down Expand Up @@ -4089,6 +4097,8 @@ test(1140, as.data.table(X), data.table(a=c(1:2,1L), b=c(1:3)),
test(1141.1, data.table(a=1:2, b=1:3), data.table(a=c(1L,2L,1L), b=1:3), warning="Item 1 has 2 rows but longest item has 3; recycled")
test(1141.2, data.table(a=1:2, data.table(x=1:5, y=6:10)), data.table(a=c(1L,2L,1L,2L,1L), x=1:5, y=6:10), warning="Item 1 has 2 rows but longest item has 5; recycled")
test(1141.3, data.table(a=1:5, data.table(x=c(1,2), y=c(3,4))), data.table(a=c(1:5), x=c(1,2,1,2,1), y=c(3,4,3,4,3)), warning="Item 2 has 2 rows but longest item has 5; recycled")
x = structure(list(1, 2), class = c("list", "data.table"))
test(1141.4, as.data.table(x), data.table(V1=c(1), V2=c(2)))

# Fix for bug #79 - DT[, foo()] returns function definition.
DT <- data.table(a=1:2)
Expand Down
Loading