#r #rcpp
#r #rcpp
Вопрос:
Кто-нибудь знает, что происходит со следующим кодом R?
library(inline)
increment <- cfunction(c(a = "integer"), "
INTEGER(a)[0] ;
return R_NilValue;
")
print_one = function(){
one = 0L
increment(one)
print(one)
}
print_one() # prints 1
print_one() # prints 2
Напечатанные результаты равны 1, 2. Замена one = 0L
на one = integer(1)
дает результат 1, 1.
Просто для пояснения. Я знаю, что передаю переменную one
по ссылке на функцию C, поэтому ее значение должно измениться (стать 1
). Чего я не понимаю, так это того, почему сброс one = 0L
, похоже, не имеет никакого эффекта после первого вызова print_one
(второй вызов print_one
печатает 2
вместо 1
).
Комментарии:
1. R использует семантику вызова по значению с реализацией копирования при записи, и если вы пишете код на C, который взаимодействует с R, ожидается, что вы будете выполнять копирование при записи самостоятельно. Вам не разрешается изменять аргументы функции подобным образом.
2. Мне просто любопытно, что здесь происходит. Почему при последующих вызовах
print_one
сбросone=0L
не имеет никакого эффекта (по крайней мере, кажется, что это происходит)?3. Я не думаю, что этот вопрос имеет какое-либо отношение к пакету Rcpp (или встроенному). Удален тег rcpp.
4. rcpp — это пакет-преемник inline, написанный тем же автором (Дирк Эдделбюттель). Общая рекомендация заключается в том, что вы должны использовать rcpp в будущем
Ответ №1:
Это действительно (как намекнул последний комментарий) имеет мало общего с Rcpp. На самом деле это в основном касается .C()
интерфейса, используемого старым inline
пакетом, и здесь по cfunction
подходу в вопросе.
Это приводит к двум ответам.
Во-первых, консенсус среди разработчиков R заключается в том, что .C()
он устарел и больше не должен использоваться. Соответствующие инструкции можно найти в списках r-devel и r-package-devel . .C()
использует простые старые типы в качестве указателей в интерфейсе, поэтому здесь целочисленное значение передается как int*
по ссылке и может быть изменено.
Если мы переключимся на Rcpp
uses и, следовательно, на базовый .Call()
интерфейс, используя только SEXP
типы для ввода и вывода, тогда int
по ссылке не передается. Таким образом, код ведет себя и печатает только 0
:
Rcpp::cppFunction("void increment2(int a) { a ; }")
print_two <- function(){
two <- 0L
increment2(two)
print(two)
}
print_two() # prints 0
print_two() # prints 0
Наконец, Rcpp
(capital R), конечно, не является «преемником» inline
(поскольку он делает намного больше, чем inline
, но он среди всех своих функциональных возможностей является (примерно с 2013 года) квази-заменой атрибутов inline
in Rcpp. Итак, с Rcpp «как есть» примерно с 2013 года вам больше не нужны примеры и подход inline
.