Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Modules vignette review#982

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 ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
Changes from1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
PrevPrevious commit
NextNext commit
Major package section review; cover sourceCpp usage.
* Focus on recommended usage via loadModule with example * General review, also covering exports.* New section about using the convenient sourceCpp.
  • Loading branch information
@riccardoporreca
riccardoporreca committedAug 5, 2019
commit32b9327394dbe009536b08eebcae959bbcae56da
208 changes: 160 additions & 48 deletionsvignettes/Rcpp-modules.Rmd
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -73,6 +73,7 @@ skip_final_break: true
# Produce a pinp document
output: pinp::pinp

# CHECK-PR: Keep the option to run the examples? (look for params$eval)
params:
eval: FALSE

Expand DownExpand Up@@ -169,7 +170,7 @@ certain aspect of \textsl{Rcpp modules} and makes binding to simple functions
such as this one even easier. With \textsl{Rcpp attributes} we can just write

```cpp
#include <Rcpp.h>
#include <Rcpp.h>

// [[Rcpp::export]]
double norm(double x, double y) {
Expand DownExpand Up@@ -373,9 +374,10 @@ module was returned by the `cxxfunction()` (from the \pkg{inline}
package) as callable R function `fx` from which we can extract the
relevant pointer using `getDynLib()` (again from \pkg{inline}).

Throughout the rest of the examples in this document, we always assume that the \proglang{C++}
code defining a module is used to create an object `fx` via a similar call
to `cxxfunction`.
Throughout the rest of the examples in this document, we always assume that the
\proglang{C++} code defining a module is used to create an object `fx` via a
similar call to `cxxfunction`. As an alternative, one can also use `sourceCpp`
as described in Section \ref{sec:modules-sourceCpp}.

A module can contain any number of calls to `function` to register
many internal functions to \proglang{R}. For example, these 6 functions:
Expand DownExpand Up@@ -973,7 +975,7 @@ private:
};

RCPP_MODULE(yada){
using namespace Rcpp;
using namespace Rcpp;

class_<World>("World")

Expand DownExpand Up@@ -1158,53 +1160,162 @@ v[[ 0L ]]
v$as.vector()
```

# Using modules in other packages {#sec:package}
<!-- CHECK-PR: sourceCpp is pretty convenient, OK to add as new section? -->
<!-- If not, the content of yada.cpp should be shown in the package section -->
## Loading modules via sourceCpp {#sec:modules-sourceCpp}

As an alternative to the explicit creation of a `Module` object using the
\pkg{inline} package via `cxxfunction` and `getDynLib`, it is possible to use
the `sourceCpp` function, accepting \proglang{C++} source code as either a
`.cpp` file or a character string. The main differences with this approach are:

- The `Rcpp.h` header file must be explicitly included.
- The content of the module (\proglang{C++} functions and classes) are
implicitly exposed and made available to \proglang{R} as individual objects, as
opposed to being accessed from a `Module` object with the `$` extractor.

Note that this is similar to exposing modules in \proglang{R} packages using
`loadModule`, described in Section \ref{sec:package-namespace-loadModule} below.

As an example, consider a file called `yada.cpp` containing the following
\proglang{C++} code:

```{Rcpp}
#include <Rcpp.h>
std::string hello() {
return "hello";
}
void bla() {
Rprintf("hello\\n");
}
void bla2( int x, double y) {
Rprintf("hello (x = %d, y = %5.2f)\\n", x, y);
}

class World {
public:
World() : msg("hello") {}
void set(std::string msg) { this->msg = msg; }
std::string greet() { return msg; }

private:
std::string msg;
};

RCPP_MODULE(yada){
using namespace Rcpp;

function("hello" , &hello);
function("bla" , &bla);
function("bla2" , &bla2);

class_<World>("World")
.constructor()
.method("greet", &World::greet)
.method("set", &World::set)
;
}
```

```{r}
sourceCpp('yada.cpp')
```

\proglang{C++} functions `hello`, `bla`, `bla2` and class `World` will be
readily available in \proglang{R}:

## Namespace import/export
```{r, eval=params$eval}
hello()
bla()
bla2(42, 0.42)
w <- new(World)
w$greet()
w$set("hohoho")
w$greet()
```

### Import all functions and classes
# Using modules in other packages {#sec:package}

## Namespace import

When using \pkg{Rcpp} modules in a packages, the client package needs to
import \pkg{Rcpp}'s namespace. This is achieved by adding the
following line to the `NAMESPACE` file.

<!-- CHECK-PR: is this chunk needed at all? -->
```{r, echo=FALSE,eval=TRUE}
options( prompt = " ", continue = " " )
```

```{r, eval=FALSE}
```{r}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I feel like there was also a need to add:

import(methods)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I double-checked using the package produced byRcpp::Rcpp.package.skeleton(), removed the DESCRIPTION and NAMESPACE imports ofmethods and things seem to still work.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Thanks for checking that. I will merge this PR but that whole aspect may be worth looking into in another ticket. This changed over the years, and maybe describing just one simple (working) setup is best.

import(Rcpp)
```

In some case we have found that explicitly naming a symbol can be preferable:

```{r, eval=FALSE}
```{r}
import(Rcpp, evalCpp)
```

## Load the module
## Load the module in the namespace

### Load the module content via loadModule {#sec:package-namespace-loadModule}

Starting with release 0.9.11, the preferred way for loading a module directly
into a package namespace is by calling the `loadModule()` function, which takes
the module name as an argument and exposes the content of the module
(\proglang{C++} functions and classes) as individual objects in the namespace.
It can be placed in any `.R` file in the package. This is useful as it allows to
load the module from the same file as some auxiliary \proglang{R} functions
using the module.

Consider a package \pkg{testmod} defining a module `yada` in the source file
`src/yada.cpp`, with the same content as defined above in
Section \ref{sec:modules-sourceCpp} above

Then, `loadModule` is called in the package's \proglang{R} code to expose all
\proglang{C++} functions and classes as objects `hello`, `bla`, `bla2`, `World`
into the package namespace:

```{r}
loadModule("yada", TRUE)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Perhaps switch this to a namespace function call?

Suggested change
loadModule("yada", TRUE)
Rcpp::loadModule("yada", TRUE)

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

This is surely a valid point, although this approach does not seem to be used across other Rcpp vignettes.

eddelbuettel reacted with laugh emoji
```

Provided the objects are also exported (see Section \ref{sec:package-exports} below), this makes them readily
available in \proglang{R}:

### Deprecated older method using loadRcppModules
```{r}
library(testmod)
hello()
bla()
bla2(42, 0.42)
w <- new(World)
w$greet()
w$set("hohoho")
w$greet()
```

The `loadModule` function has an argument `what` to control which objects are
exposed in the package namespace. The special value `TRUE` means that all
objects are exposed.

Note: This approach is deprecated as of Rcpp 0.12.5, and now triggers a warning
message. Eventually this function will be withdrawn.
### Deprecated legacy method using loadRcppModules

The simplest way to load all functions and classes from a module directly
into a package namespace used to be to use the `loadRcppModules` function
Prior to release 0.9.11, where `loadModule` was introduced,
loading all functions and classes from a module
into a package namespace was achieved using the `loadRcppModules` function
within the `.onLoad` body.

```{r, eval=FALSE}
```{r}
.onLoad <- function(libname, pkgname) {
loadRcppModules()
}
```

This will look in the package's DESCRIPTION file for the `RcppModules`
This will look in the package's`DESCRIPTION` file for the `RcppModules`
field, load each declared module and populate their contents into the
package's namespace. For example, both the \pkg{testRcppModule} package
(which is part of large unit test suite for \pkg{Rcpp}) and the package
created via `Rcpp.package.skeleton("somename", module=TRUE)` have this
declaration:
package's namespace. For example, a package defining modules
`yada`, `stdVector`, `NumEx` would have this declaration:

```
RcppModules: yada, stdVector, NumEx
Expand All@@ -1215,64 +1326,65 @@ with a default value of `TRUE`. With this default value, all content
from the module is exposed directly in the package namespace. If set to
`FALSE`, all content is exposed as components of the module.

### Preferred current method using loadModule

Starting with release 0.9.11, an alternative is provided by the
`loadModule()` function which takes the module name as an argument.
It can be placed in any `.R` file in the package. This is useful as it allows to load
the module from the same file as some auxiliary \proglang{R} functions using the
module. For the example module, the equivalent code to the `.onLoad()`
use shown above then becomes

```{r, eval=FALSE}
loadModule("yada")
loadModule("stdVector")
loadModule("NumEx")
```

This feature is also used in the new Rcpp Classes introduced with Rcpp 0.9.11.
Note: This approach is **deprecated** as of Rcpp 0.12.5, and now triggers a
warning message. Eventually this function will be withdrawn.

### Just expose the module

Alternatively, it is possible to just expose the module to the user of the package,
Alternatively to exposing a module's content via `loadModule`,
it is possible to just expose the module object to the users of the package,
and let them extract the functions and classes as needed. This uses lazy loading
so that the module is only loaded the first time the user attempts to extract
a function or a class with the dollar extractor.

```{r, eval=FALSE}
```{r}
yada <- Module( "yada" )

.onLoad <- function(libname, pkgname) {
# placeholder
}
```

<!-- CHECK-PR: is this chunk needed at all? -->
```{r, echo=FALSE,eval=TRUE}
options(prompt = "> ", continue = "+ ")
```

Provided `yada` is properly exported, the functions and classes are
accessed as e.g. `yada$hello`, `yada$World`.

## Namespace exports {#sec:package-exports}

The content of modules or the modules as a whole, exposed as objects in the
package namespace, must be exported to be visible to users of the package. As
for any other object, this is achieved by the appropriate `export()` or
`exportPattern()` statements in the `NAMESPACE` file. For instance, the
functions and classes in the `yada` module considered above can be exported as:

```
export(hello, bla, bla2, World)
```


## Support for modules in skeleton generator

The `Rcpp.package.skeleton` function has been improved to help
\pkg{Rcpp} modules. When the `module` argument is set to `TRUE`,
the skeleton generator installs code that uses a simple module.
Creating a new package using \textsl{Rcpp modules} is easiest via the call to
`Rcpp.package.skeleton()` with argument `module=TRUE`.

```{r, eval=FALSE}
```{r}
Rcpp.package.skeleton("testmod", module = TRUE)
```

Creating a new package using \textsl{Rcpp modules} is easiest via the call to
`Rcpp.package.skeleton()` with argument `module=TRUE` as a working
package with three example Modules results.
This will install code providing three example modules, exposed using
`LoadModule`.

## Module documentation

\pkg{Rcpp} defines a `prompt` method for the
`Module` class, allowing generation of a skeleton of an Rd
file containing some information about the module.

```{r, eval=FALSE}
```{r}
yada <- Module("yada")
prompt(yada, "yada-module.Rd")
```
Expand Down

[8]ページ先頭

©2009-2025 Movatter.jp