The Big R-Book. Philippe J. S. De Brouwer

Чтение книги онлайн.

Читать онлайн книгу The Big R-Book - Philippe J. S. De Brouwer страница 44

The Big R-Book - Philippe J. S. De Brouwer

Скачать книгу

all, the logic of the way a balance is found is only in one place and in every call the same. Second, it becomes easier to pass on information and keep code lean: if you will need the balance all you have to do is import the object account and you inherit all its functionality.

      There are other ways to keep code clean, for example creating an object, that is a savings account, will automatically inherit the functionality and data that all accounts share. So it becomes easy to create other types of accounts that are based on one primordial object account. For example, current accounts, savings accounts and investment accounts can all inherit from the object “account.” One of the basic things that all accounts will share is for example the way ownership works and how transactions are allowed. This can be programmed once and used in all types of accounts that inherit from this one. If necessary, this can even be overwritten, if there one type of account that uses another logic.

      The following code creates, for example, an attribute data_source within the object df.

      L <- list(matrix(1:16, nrow=4)) L$data_source <- “mainframe 1” L$get_data_src <- function(){L$data_source} print(L$get_data_src()) ## [1] “mainframe 1”

      In many ways, the list object (and many other objects) act as manifestations of objects that can freely be expanded. So already in the Section 4.3.6 “Lists” on page 41, we have used the object oriented capabilities of R explicitely. This might be a little bewildering and leaves the reader probably wondering what is the true object model behind R. Well, the answer is that there is not one but rather four types of classes.

      Multiple OO systems ready to use in R. R's OO systems differ in how classes and methods are defined:

      1 Base types. This is not a true OO system as it misses critical features like inheritance and flexibility. However, this underlies all other OO systems, and hence, it is worth to understand them a little. They are typically thought of as a struct in C.C

      2 S3. S3 is a popular class type in R. It is very different from the OO implementation that is in most programming languages such as C++, C#, PHP, Java, etc. In those languages one would expect to pass a message to an object (for example ask the object my_account its balance as via the method my_curr_acc.balance(). The object my_account is of the type account and hence it is the logic that sits there that will determine what function balance() is used. These implementations are called message-passing systems., S3 uses a different logic: it is a generic-function implementation of the OO logic. The S3 object can still have its own methods, but there are generic functions that will decide which method to use. For example, the function print() will do different things for a linear model, a dataset, or a scalar.

      3 Then there is also S4, which works very similarly to S3, but there is a formal declaration of the object (its definition) and it has special helper functions for defining generics and methods. S4 also allows for “multiple dispatch,” which means that generic functions can pick methods based on the class of any number of arguments, not just one.

      4 Reference classes (RC) are probably closest to what you would expect based on your C++ or C# experience. RC implements a message-passing OO system in R. This means that a method (function) will belong to a class, and it is not a generic method that will decide how it behaves on different classes. The RC implementation uses the $. This means that a call to the function balance of an object of class account will look like my_account$dbalance(). RC objects in R are “mutable.” This means that they don't follow R's general logic “copy-on-modify” semantics, but are modified in place. This allows for difficult to read code but is invaluable to solve problems that cannot be solved in S3 or S4.

       C++

       C#

       RC – reference class

       struct

      # Define a string: acc <- “Philippe” # Force an attribute, balance, on it: acc$balance <- 100 ## Warning in acc$balance <- 100: Coercing LHS to a list # Inspect the result: acc ## [[1]] ## [1] “Philippe” ## ## $balance ## [1] 100

      This means that the base type holds information on how the object is stored in memory (and hence how much bytes it occupies), what variables it has, etc. The base types are part of R's code and compiled, so it is only possible to create new ones by modifying R's source code and recompiling. When thinking about the base types, one readily recalls all the types that we studied in the previous sections such as integers, vectors, matrices are base types. However, there are more exotic ones such as environments, functions, calls.

      Some conventions are not straightforward but deeply embedded in R and many people's code, some things might be somewhat surprising. Consider the following code:

      # a function build in core R typeof(mean) ## [1] “closure” is.primitive(mean) ## [1] FALSE # user defined function are “closures: add1 <- function(x) {x+1} typeof(add1) ## [1] “closure” is.function(add1) ## [1] TRUE is.object(add1) ## [1] FALSE

       is.primitive()

       typeof()

       is.function()

       is.object()

      The importance of these struct-based base type is that all other object types are built upon these: S3 objects are directly build on top of the base types, S4 objects use a special-purpose base type, and RC objects are a combination of S4 and environments (which is also a base type).

      The function is.object() returns true both for S3 and S4 objects. There is no base function that allows directly to test if an object is S3, but there is a to test to check if an object is S4. So we can test if something is S3 as follows.

      # is.S3 #

Скачать книгу