class: center, middle, inverse, title-slide .title[ # An Introduction to Rcpp Modules ] .subtitle[ ## Jonathan Berrisch ] .author[ ### University of Duisburg-Essen ] .date[ ### 2022-06-21 ] --- name: motivation # Outline </br> </br> 1. R and C++ Classes - What is a class? - Why are classes useful? 2. Rcpp Modules - How to write a module? - How to use a module? 3. From-Scratch Example 4. Beyond this talk: What you want to learn next --- # What's a class in R? .pull-left[ </br> Unlike most other programming languages, R has a three-class system. These are S3, S4, and Reference Classes. </br> #### S3 Class S3 is the simplest yet the most popular OOP system and it lacks formal definition and structure. An object of this type can be created by just adding an attribute to it. [[geeksforgeeks](https://www.geeksforgeeks.org/classes-in-r-programming/)] ] .pull-right[ ```r # Data x <- 1:10 class(x) ``` ``` ## [1] "integer" ``` ```r # Methods sum(x) ``` ``` ## [1] 55 ``` ```r mean(x) ``` ``` ## [1] 5.5 ``` ] --- # What's a class in C++? .pull-left[ </br> .center[A class in C++ is a user-defined type or data structure declared with the keyword *class* that has data and functions (also called member variables and member functions) as its members whose access is governed by the three access specifiers *private*, protected or **public**. [[Wikipedia](https://en.wikipedia.org/wiki/C%2B%2B_classes)]] </br> **Private** objects can only be accessed within the class. **Public** objects can be accessed from outside and inside. ] .pull-right[ ```cpp class Student { public: // Member variables std::string name; int age; bool male; // Constructor Student(std::string name, int age, bool male); // Getters std::string GetName(); int GetAge(); bool IsMale(); // Methods bool AllowedToDrink(); }; ``` ] --- # What's nice about classes? </br> Classes let you *bundle code and data together* in a single unit </br> C++ code can be written in a very modular way </br> Input / Output is easier compared to only using C++ functions with `Rcpp` </br> Users may expect some *methods* to be implemented (`print`, `summarise`, `plot`) </br> Rcpp modules are a blessing for debugging C++ code --- class: sydney-blue, center, middle # How to use C++ classes with R? --- # Rcpp Modules .pull-left[ #### Attributes "*Rcpp attributes provide a high-level syntax for declaring C++ functions as callable from R* [...]" [Rcpp-attributes.pdf](https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-attributes.pdf). #### Modules "*Rcpp modules allow programmers to expose C++ functions and classes to R* [...]" [Rcpp-modules.pdf](https://cran.r-project.org/web/packages/Rcpp/vignettes/Rcpp-modules.pdf). #### Both Using both together is possible: [RcppExtModEx](https://github.com/BerriJ/RcppExtModEx) ] .pull-right[ ```cpp // Rcpp Attributes // [[Rcpp::export]] int plusone( const int &x) { int y = x + 1; return y; } ``` ```cpp // Rcpp Modules // Expose (some of) the Student class RCPP_MODULE(RcppStudentEx){ Rcpp::class_<Student>("Student") .constructor<std::string, int, bool>() .method("GetName", &Student::GetName) .field("name", &Student::name) .method("AllowedToDrink", &Student::AllowedToDrink); } ``` ] --- class: sydney-blue, center, middle # Example: The Student class --- class: scrollable-slide # Student example .pull-left-2[ #### Student class example We implement a simple student class No package involved. Just `Rcpp` and `sourceCpp` Most parts are from [GormAnalysis](https://www.gormanalysis.com/blog/exposing-a-cpp-student-class-with-rcpp/) [This repository](https://github.com/r-pkg-examples/rcpp-modules-student) shows how to bundle it into a package and nicely structure everything. We will skip the structuring and just make one big file (which I do not recommend) ] .scroll-output[ ```cpp // ... student.cpp #include <Rcpp.h> #include <string> // Class definition class Student { public: // Member variables std::string name; int age; bool male; // Constructor Student(std::string name, int age, bool male); // Getters std::string GetName(); int GetAge(); bool IsMale(); // Methods bool AllowedToDrink(const int boundary); }; // Constructor Student::Student(std::string name, int age, bool male) { this->name = name; this->age = age; this->male = male; } // Methods // No inputs needed! std::string Student::GetName() { return name; } int Student::GetAge() { return age; } bool Student::IsMale() { return male; } bool Student::AllowedToDrink(const int boundary) { bool answer = age >= boundary; return answer; } RCPP_MODULE(RcppStudentEx) { Rcpp::class_<Student>("Student") .constructor<std::string, int, bool>() .method("GetName", &Student::GetName) .method("GetAge", &Student::GetAge) .method("IsMale", &Student::IsMale) .field("name", &Student::name) .field("age", &Student::age) .field("male", &Student::male) .method("AllowedToDrink", &Student::AllowedToDrink); } ``` ] --- # Student example .pull-left-4[ #### The R Side of things Now that we have `student.cpp` finished we can use it from R: ```r library(Rcpp) sourceCpp("student.cpp") ``` ```r jon <- new(Student, "Jonathan", 15, TRUE) str(jon) ``` ``` ## Reference class 'Rcpp_Student' [package ".GlobalEnv"] with 3 fields ## $ age : int 15 ## $ male: logi TRUE ## $ name: chr "Jonathan" ## and 20 methods, of which 6 are possibly relevant: ## AllowedToDrink, finalize, GetAge, GetName, initialize, IsMale ``` ] .pull-right-4[ ```r jon$AllowedToDrink(18) ``` ``` ## [1] FALSE ``` ```r jon$age <- 29 # We get write access! :) jon$AllowedToDrink(18) ``` ``` ## [1] TRUE ``` ```r jon$name # .field may suffice ... ``` ``` ## [1] "Jonathan" ``` ```r jon$GetName() # ... but if you like getters ``` ``` ## [1] "Jonathan" ``` ] --- name: conclusion # Wrap-Up .pull-left[ #### What we learned today: Classes: What and Why Public vs. Private Rcpp: Attributes vs. Modules Classes from C++ to R using Rcpp Modules Constructors are called when a new instance gets created Fields give (read and write) access to member variables Using classes gives you a lot of flexibility ... ... compared to writing standalone functions which essentially need the same data ] .pull-right[ #### What we still want to learn: Initializing variables with default values Restructure C++ Code: [start here](https://github.com/r-pkg-examples/rcpp-modules-student) - Class declaration (student.h) - Class implementation (student.cpp) - Rcpp Module (student_export.cpp) - Putting everything into a Package #### What we could learn: What and how: destructors (I used one [here](https://github.com/BerriJ/profoc/blob/main/inst/include/clock.h)) Still excited? [start here](https://github.com/BerriJ/RcppExtModEx) ] <a href="https://github.com/BerriJ" class="github-corner" aria-label="View source on Github"><svg width="80" height="80" viewBox="0 0 250 250" style="fill:#f2f2f2; color:#212121; position: absolute; top: 0; border: 0; right: 0;" aria-hidden="true"><path d="M0,0 L115,115 L130,115 L142,142 L250,250 L250,0 Z"></path><path d="M128.3,109.0 C113.8,99.7 119.0,89.6 119.0,89.6 C122.0,82.7 120.5,78.6 120.5,78.6 C119.2,72.0 123.4,76.3 123.4,76.3 C127.3,80.9 125.5,87.3 125.5,87.3 C122.9,97.6 130.6,101.9 134.4,103.2" fill="currentColor" style="transform-origin: 130px 106px;" class="octo-arm"></path><path d="M115.0,115.0 C114.9,115.1 118.7,116.5 119.8,115.4 L133.7,101.6 C136.9,99.2 139.9,98.4 142.2,98.6 C133.8,88.0 127.5,74.4 143.8,58.0 C148.5,53.4 154.0,51.2 159.7,51.0 C160.3,49.4 163.2,43.6 171.4,40.1 C171.4,40.1 176.1,42.5 178.8,56.2 C183.1,58.6 187.2,61.8 190.9,65.4 C194.5,69.0 197.7,73.2 200.1,77.6 C213.8,80.2 216.3,84.9 216.3,84.9 C212.7,93.1 206.9,96.0 205.4,96.6 C205.1,102.4 203.0,107.8 198.3,112.5 C181.9,128.9 168.3,122.5 157.7,114.1 C157.9,116.9 156.7,120.9 152.7,124.9 L141.0,136.5 C139.8,137.7 141.6,141.9 141.8,141.8 Z" fill="currentColor" class="octo-body"></path></svg></a><style>.github-corner:hover .octo-arm{animation:octocat-wave 560ms ease-in-out}@keyframes octocat-wave{0%,100%{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}@media (max-width:500px){.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave 560ms ease-in-out}}</style>