Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Document proxy object 'const' not being constant in Rcpp FAQ #628

Closed
eddelbuettel opened this issue Jan 11, 2017 · 3 comments
Closed

Document proxy object 'const' not being constant in Rcpp FAQ #628

eddelbuettel opened this issue Jan 11, 2017 · 3 comments

Comments

@eddelbuettel
Copy link
Member

See eg #627 for a very recent example. That should have gone to the FAQ ages ago.

@coatless
Copy link
Contributor

coatless commented Mar 23, 2017

Proposed entry in the inaugural Section 5: Known Issues

Title: Rcpp changed the (const) object I passed by value

Text:

\pkg{Rcpp} objects are wrappers around the underlying \R objects' \code{SEXP} , or S-expression. The \code{SEXP} is a pointer variable that holds the location of where the \R object data has been stored \citep[][Section 1.1]{R:Internals}. That is to say, the \code{SEXP} does \textit{not} hold the actual data of the \R object but merely a reference to where the data resides. When creating a new \pkg{Rcpp} object for an \R object to enter \proglang{C++}, this object will use the same \code{SEXP} that powers the original \R object if the types match otherwise a new \code{SEXP} must be created to be type safe. In essence, the underlying \code{SEXP} objects are passed by reference without explicit copies being made into \proglang{C++}. We refer to this arrangement as a \textit{proxy model}.

As for the actual implementation, there are a few consequences of the proxy model. The foremost consequence within this paradigm is that pass by value is really a pass by reference. In essence, the distinction between the following two functions is only visual sugar:

void implicit_ref(NumericVector X);
void explicit_ref(NumericVector& X);

In particular, when one is passing by value what occurs is the instantiation of the new \pkg{Rcpp} object that uses the same \code{SEXP} for the \R object. As a result, the \pkg{Rcpp} object is ``linked'' to the original \R object. Thus, if an operation is performed on the \pkg{Rcpp} object, such as adding 1 to each element, the operation also updates the \R object.

#include<Rcpp.h>
// [[Rcpp::export]]
void implicit_ref(Rcpp::NumericVector X){
X = X + 1.0;
}

// [[Rcpp::export]]
void explicit_ref(Rcpp::NumericVector& X){
X = X + 1.0;
}

/*** R
a <- 1.5:10.5 
b <- 1.5:10.5

# Implicit
implicit_ref(a)
a

# Explicit test
explicit_ref(b)
b
*/

There are two exceptions to this rule. The first exception is that a deep copy of the object can be made by explicit use of \code{Rcpp:clone()}. In this case, the cloned object has no link to the original \R object. However, there is a time cost associated with this procedure as new memory must be allocated and the previous values must be copied over. The second exception, which was previously foreshadowed, is encountered when \pkg{Rcpp} and \R object types do not match. One frequent example of this case is when the \R object generated from \code{seq()} or \code{a:b} reports a class of \code{"integer"} while the \pkg{Rcpp} object is setup to receive the class of \code{"numeric"} as its object is set to \code{NumericVector} or \code{NumericMatrix}. In such cases, this would lead to a new \code{SEXP} object being created behind the scenes and, thus, there would \textit{not} be a link between the \pkg{Rcpp} object and \R object.

#include<Rcpp.h>

// [[Rcpp::export]]
void num_vec_type(Rcpp::NumericVector X){
X = X + 1.0;
}

// [[Rcpp::export]]
void int_vec_type(Rcpp::IntegerVector X){
X = X + 1.0;
}

/*** R
a <- 1.5:10.5
b <- 1.5:10.5 
# View the object type
class(a)

# Correct type
num_vec_type(a)
a

# Mismatch
int_vec_type(b)
b
*/

With this being said, there is one last area of contention with the proxy model: the keyword \code{const}. Similar to the pass by value versus pass by reference conundrum, the \code{const} declaration that indicates an object cannot be modified is just cosmetic because of the underlying R semantics and data structures. There is no ability to force the appropriate \proglang{C++} behavior that traditionally governs \code{const} declarations. In some cases, the compiler may provide warnings that a \code{const} object is being modified. However, it is best to not rely upon the \code{const} keyword.

@eddelbuettel
Copy link
Member Author

That's pretty good, thank you.

@eddelbuettel
Copy link
Member Author

Made some small edits within.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants