В книге "Программное обеспечение для анализа данных: программирование с помощью R" Джон Чамберс подчеркивает, что функции, как правило, не должны быть написаны для их побочного эффекта; скорее, что функция должна возвращать значение без изменения каких-либо переменных в своей вызывающей среде. И наоборот, запись хорошего script с использованием объектов data.table должна специально избегать использования назначения объекта с помощью <-, обычно используемого для хранения результата функции.
Во-первых, это технический вопрос. Представьте себе функцию R, называемую proc1, которая принимает объект data.table x в качестве аргумента (в дополнение к, возможно, другим параметрам). proc1 возвращает NULL, но изменяет x с помощью :=. Из того, что я понимаю, proc1 вызов proc1(x=x1) делает копию x1 только из-за того, как работает promises. Однако, как показано ниже, исходный объект x1 все еще изменяется proc1. Почему/как это?
> require(data.table)
> x1 <- CJ(1:2, 2:3)
> x1
V1 V2
1: 1 2
2: 1 3
3: 2 2
4: 2 3
> proc1 <- function(x){
+ x[,y:= V1*V2]
+ NULL
+ }
> proc1(x1)
NULL
> x1
V1 V2 y
1: 1 2 2
2: 1 3 3
3: 2 2 4
4: 2 3 6
>
Кроме того, кажется, что использование proc1(x=x1) не является медленным, чем выполнение процедуры непосредственно на x, что указывает на то, что мое смутное понимание promises неверно и что они работают в режиме передачи по ссылке
> x1 <- CJ(1:2000, 1:500)
> x1[, paste0("V",3:300) := rnorm(1:nrow(x1))]
> proc1 <- function(x){
+ x[,y:= V1*V2]
+ NULL
+ }
> system.time(proc1(x1))
user system elapsed
0.00 0.02 0.02
> x1 <- CJ(1:2000, 1:500)
> system.time(x1[,y:= V1*V2])
user system elapsed
0.03 0.00 0.03
Итак, учитывая, что передача аргумента data.table функции не добавляет времени, это позволяет писать процедуры для объектов data.table, включающих как скорость data.table, так и обобщаемость функции. Однако, учитывая, что Джон Чамберс сказал, что функции не должны иметь побочных эффектов, действительно ли "нормально" писать этот тип процедурного программирования в R? Почему он утверждал, что побочные эффекты "плохие"? Если я проигнорирую его совет, какие ошибки я должен знать? Что я могу сделать, чтобы написать "хорошие" методы data.table?