Adicionando novas colunas a uma referência de data.table em uma função que nem sempre funciona
Ao escrever um pacote que depende dedata.table
, Eu descobri um comportamento estranho. Eu tenho uma função que remove e reordena algumas colunas por referência e funciona muito bem, significando odata.table
Eu passei foi modificado sem atribuir a saída da função. Eu tenho outra função que adicionaNovo colunas, no entanto, mas essas alterações nem sempre persistem nodata.table
que foi passado.
Aqui está um pequeno exemplo:
library(data.table) # I'm using 1.9.4
test <- data.table(id = letters[1:2], val=1:2)
foobar <- function(dt, col) {
dt[, (col) := 1]
invisible(dt)
}
test
# id val
#1: a 1
#2: b 2
saveRDS(test, "test.rds")
test2 <- readRDS("test.rds")
all.equal(test, test2)
#[1] TRUE
foobar(test, "new")
test
# id val new
#1: a 1 1
#2: b 2 1
foobar(test2, "new")
test2
# id val
#1: a 1
#2: b 2
O que aconteceu? O que há de diferentetest2
? Eu posso modificar as colunas existentes no local:
foobar(test, "val")
test
# id val new
#1: a 1 1
#2: b 1 1
foobar(test2, "val")
test2
# id val
#1: a 1
#2: b 1
Mas adicionando atest2
ainda não funciona:
foobar(test2, "someothercol")
.Last.value
# id val someothercol
#1: a 1 1
#2: b 1 1
test2
# id val
#1: a 1
#2: b 1
Não consigo identificar todos os casos em que vejo esse comportamento, mas salvar e ler no RDS é o primeiro caso que posso replicar com segurança. Escrever e ler de um CSV não parece ter o mesmo problema.
Esta é uma questão de ponteiro alaesse problema, como serializar uma tabela de dados destrói os ponteiros superalocados? Existe uma maneira simples de restaurá-los? Como posso procurá-los dentro da minha função, para restaurar os ponteiros ou erros, se a operação não funcionar?
Eu sei que posso atribuir a saída da função como uma solução alternativa, mas isso não é muitodata.table
-y. Isso também não criaria uma cópia temporária na memória?
Arun instruiu que é realmente um problema de ponteiro, que pode ser diagnosticado comtruelength
e consertado comsetDT
oualloc.col
. Encontrei um problema ao encapsular sua solução em uma função (continuando no código acima):
func <- function(dt) {if (!truelength(dt)) setDT(dt)}
func2 <- function(dt) {if (!truelength(dt)) alloc.col(dt)}
test2 <- readRDS("test.rds")
truelength(test2)
#[1] 0
truelength(func(test2))
#[1] 100
truelength(test2)
#[1] 0
truelength(func2(test2))
#[1] 100
truelength(test2)
#[1] 0
Portanto, parece que a cópia local dentro da função está sendo modificada corretamente, mas a versão de referência não. Por que não?