В книге "Программное обеспечение для анализа данных: программирование с помощью 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?