Many times R programmers would like to add methods for already existing functions. They may also want to add new generic function or already existing generic functions. In this section, you will learn some guidelines how to do this with different examples. You can always make modifications to meet your needs. You will also learn about the “informal” class system from S3.
One of the most essential functions for methods is the “NextMethod()” function, which dispatches the next method. It is normal for methods like these methods to make a few changes to the arguments, sends the information to the “NextMethod()”, and receives the results with a little modification. The following example will show you how this method works:
// The NextMethod() receives the information f.data <- function(x)
{ x <- as.matrix(x) NextMethod(“f”) }
You should also take into consideration the “predict.glm()” function that obtains predictions and optionally estimates standard errors. This function calls the “predict.lm()” function directly, but basically you could use the next method. This method is not frequently used in R. You must also be aware that there are S and R programming differences, but can work as seen in the above example with the “NextMethod()”.
As a programmer, when you write any method, bear in mind that is called by another method with the
“NextMethod()” function. The arguments must be corresponding to the previous method.
Additionally, you cannot predict which “NextMethod()” you will choose or which end user will call the generic functions necessary for passing the arguments to the next method. For this procedure to work, you will need to have a method with all the generic arguments.
Do not believe that a method needs to accept only the arguments that it needs. In the S program, the
“predict.glm()” function does not have the “…” argument, although the “predict()” function does.
Eventually, the “predict.glm()” function needs the “dispersion” argument to handle too much dispersion. Since the “predict.lm()” function does not have a “dispersion” argument nor the “…”
argument, the “NextMethod()” function can no longer be implemented.
Note : The two direct calls to the “predict.lm()” function continues to reside in the “predict.glm()” function within R.
The end user can use positional matching when calling the generic function. The arguments to a method can also be called by the UseMethod() function.
Note : The method must have arguments that are in the same order as the generic function.
The following example will show you how the generic function “solution” is defined:
> solution <- function(x, center = TRUE, solution = TRUE)
> UseMethod(“solution”)
The following example creates a method based on the “solution” generic function:
> solution.calc <- function(x, solution = FALSE, …) {}
The above method has the “x” argument with the “calc” class, which is implemented by doing the following:
> solution(x, , TRUE)
> solution(x, solution = TRUE)
The above example is capable of doing different things to accommodate the end user. You could change this method a little, where the default is used when the end user calls the “solution(x)” function for example. The following example will show you how you could implement the “solution()”
function:
> solution.shapes <- function(x, center, solution = TRUE)
> NextMethod(“solution”)
In the above example, “x” has the class c(“shapes”, “calc”). The default that is specified in method, is the one that is used. However, the default that is specified in the generic function maybe the one the user will see. Therefore, it is recommended that if generic functions specify the defaults, then all the methods should implement the same defaults. The best way to look to go about these recommendations is to ensure that all the generic functions are simple.
The following example will show how to simplify a generic function:
> solution <- function(x, …)
> UseMethod(“solution”)
You will only need to add the arguments and the defaults to the generic function if they are necessary for all the required methods.
S3 Classes
In this section, you will learn about S3 classes and how basic data types and scripting is used within these classes.
First thing that you should know is that everything is treated like objects in R. This concept was demonstrated in functions. Many of the R objects created in a session have attributes that are related to them. One of the most commonly used attributes related to this object is its class.
You can set the class attribute with the “class” command. Bear in mind that the class is a vector that allows object to inherit from many classes. It also allows you to specify the inheritance order of complex classes. The class command is also used to determine the classes that are related to an object.
R provides efficient memory management of S3 classes. It provides more flexibility for S3 classes over S4 classes. S4 classes require a more structured approach. When it comes down to it S3 classes are easier to work with. Since S3 classes are easier to work with, this book will focus more on them.
To understand how S3 classes work in R memory, you will need to learn about memory environments in R. This will help you create codes that are more understandable. This feature provides the flexibility.
A memory environment can be considered on the local level that comes with a set of variables. These variables can be accessed if you have the “ID” that is related to the environment. You can use various commands to manipulate and get pointers to your environments. You can also use the “assign()” and
“get()” functions to set and get the values of the variables in the environment.
The “environment()” function can be used as a pointer to the environment that is currently being used. The following example will show you how to implement “environment()”, “assign()”, “get()”,
[1] "num" "e"
> num
[1] 3
> get("num",e) [1] 3
You can create and embed environments inside other environments, as well as structure a form of hierarchy. R provides various commands to help you move around the various environment. To find out more about the different environments, enter “help(environment)” at the command line.
S3 Classes
In the previous sections, you learned about the basic concepts surrounding S3 classes. In this section, you will learn a little more. You will learn how to define a function that will create and return an object belonging to a specific class. Simply put, a list is created with some relevant elements, then the class for the list is set, and then a replica of the list is returned.
There are actually two different approaches for constructing S3 classes. The first approach is the
“Straight Forward Approach” and the second one is the “Local Environment Approach” The Straight Forward Approach is used more often and is considered easier to be very straightforward. This approach uses a list of basic properties. The Local Environment Approach uses the local environment inside the function to define the variables that are tracked by the class. This approach is more advantageous because it behaves more like the object orientation method. The downside to this approach is that it is more challenging to read the code, and it is more likely to work with pointers.
This approach is different from the way other objects are used in R.
Straight Forward Approach – This approach is more standard and is used more often in S3 classes. It allows you to use methods outside of the class. It also tracks the date that is maintained by the class, by using the rules associated with the lists. The basic concept is that the predefined function creates a list. The data entries that are tracked by the class are defined within the list. In the following example, you will notice that the defaults are specified with assigned values within the arguments. There is a new class that is appended to the class list, as well as return the list.
Caribbean <- function(booksHotel=TRUE, myFavorite="Jamaican") { mylist <- list(hasHotel = booksHotel, favoriteHotel = myFavorite) class(mylist) <- append(class(mylist),"Caribbean")
(mylist) }
In the above definition, a new function called “Caribbean” is defined and executed. You can new environment is created that is identified when you implement the “environment()”
function. The environment itself can be stored within the list that is created for the class.
The variables within the local scope can be accessed based on the environment’s identification.
In the following example, this approach needs to be in more detail, but you will understand what needs to be done from the specified comments. You will better how this approach works by examining the example in detail.
// The function defines the environment.