ВУЗ: Не указан

Категория: Не указан

Дисциплина: Не указана

Добавлен: 06.04.2021

Просмотров: 876

Скачиваний: 1

ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
background image

7.2. S4

CIRCLE 7. TRIPPING ON OBJECT ORIENTATION

A list of all methods for

median

(in the current session) is found with:

methods(median)

and methods for the

"factor"

class are found with:

methods(class=’factor’)

7.1.3

inheritance

Classes can inherit from other classes. For example:

>

class(ordered(c(90, 90, 100, 110, 110)))

[1] "ordered" "factor"

Class

"ordered"

inherits from class

"factor"

. Ordered factors are factors, but

not all factors are ordered. If there is a method for

"ordered"

for a specific

generic, then that method will be used when the argument is of class

"ordered"

.

However, if there is not a method for

"ordered"

but there is one for

"factor"

,

then the method for

"factor"

will be used.

Inheritance should be based on similarity of the structure of the objects,

not similarity of the concepts for the objects. Matrices and data frames have
similar concepts. Matrices are a specialization of data frames (all columns of the
same type), so conceptually inheritance makes sense. However, matrices and
data frames have completely different implementations, so inheritance makes
no practical sense. The power of inheritance is the ability to (essentially) reuse
code.

7.2

S4 methods

S4 methods correspond to the green book.

S3 methods are simple and powerful, and a bit

ad hoc

. S4 methods remove

the

ad hoc

—they are more strict and more general. The S4 methods technology

is a stiffer rope—when you hang yourself with it, it surely will not break. But
that is basically the point of it—the programmer is restricted in order to make
the results more dependable for the user. That’s the plan anyway, and it often
works.

7.2.1

multiple dispatch

One feature of S4 methods that is missing from S3 methods (and many other
object-oriented systems) is multiple dispatch. Suppose you have an object of
class

"foo"

and an object of class

"bar"

and want to perform function

fun

on

these objects. The result of

fun(foo, bar)

40


background image

7.2. S4

CIRCLE 7. TRIPPING ON OBJECT ORIENTATION

Figure 7.1: The Simoniacs by Sandro Botticelli.

may or may not to be different from

fun(bar, foo)

If there are many classes or many arguments to the function that are sensitive
to class, there can be big complications. S4 methods make this complicated
situation relatively simple.

We saw that

UseMethod

creates an S3 generic function. S4 generic functions

are created with

standardGeneric

.

7.2.2

S4 structure

S4 is quite strict about what an object of a specific class looks like. In contrast
S3 methods allow you to merely add a

class

attribute to any object—as long

as a method doesn’t run into anything untoward, there is no penalty. A key
advantage in strictly regulating the structure of objects in a particular class is
that those objects can be used in C code (via the

.Call

function) without a

copious amount of checking.

Along with the strictures on S4 objects comes some new vocabulary. The

pieces (components) of the object are called

slots

. Slots are accessed by the

8

@

8

operator. So if you see code like:

41


background image

7.3. NSPACES

CIRCLE 7. TRIPPING ON OBJECT ORIENTATION

x@Data

that is an indication that

x

is an S4 object.

By now you will have noticed that S4 methods are driven by the

class

attribute just as S3 methods are. This commonality perhaps makes the two
systems appear more similar than they are. In S3 the decision of what method
to use is made in real-time when the function is called. In S4 the decision is
made when the code is loaded into the R session—there is a table that charts
the relationships of all the classes. The

showMethods

function is useful to see

the layout.

S4 has inheritance, as does S3. But, again, there are subtle differences. For

example, a concept in S4 that doesn’t resonate in S3 is

contains

. If S4 class

"B"

has all of the slots that are in class

"A"

, then class

"B"

contains class

"A"

.

7.2.3

discussion

Will S4 ever totally supplant S3? Highly unlikely. One reason is backward
compatibility—there is a whole lot of code that depends on S3 methods. Addi-
tionally, S3 methods are convenient. It is very easy to create a

plot

or

summary

method for a specific computation (a simulation, perhaps) that expedites anal-
ysis.

So basically S3 and S4 serve different purposes. S4 is useful for large,

industrial-strength projects. S3 is useful for

ad hoc

projects.

If you are planning on writing S4 (or even S3) methods, then you can defi-

nitely do worse than getting the book

Software for Data Analysis: Programming

with R

by John Chambers. Don’t misunderstand: this book can be useful even

if you are not using methods.

Two styles of object orientation are hardly enough. Luckily, there are the

OOP

,

R.oo

and

proto

packages that provide three more.

7.3

Namespaces

Namespaces don’t really have much to do with object-orientation. To the casual
user they are related in that both seem like an unwarranted complication. They
are also related in the sense that that seeming complexity is actually simplicity
in disguise.

Suppose that two packages have a function called

recode

. You want to use

a particular one of these two. There is no guarantee that the one you want will
always be first on the search list. That is the problem for which namespaces are
the answer.

To understand namespaces, let’s consider an analogy of a function that re-

turns a named list. There are some things in the environment of the function
that you get to see (the components that it returns), and possibly some objects
that you can’t see (the objects created in the function but not returned). A

42


background image

7.3. NSPACES

CIRCLE 7. TRIPPING ON OBJECT ORIENTATION

namespace exports one or more objects so that they are visible, but may have
some objects that are private.

The way to specify an object from a particular namespace is to use the

8

::

8

operator:

>

stats::coef

function (object, ...)
UseMethod("coef")
<environment: namespace:stats>

This operator fails if the name is not exported:

>

stats::coef.default

Error: ’coef.default’ is not an exported object

from ’namespace:stats’

There are ways to get the non-exported objects, but you have to promise not to
use them except to inspect the objects. You can use

8

:::

8

or the

getAnywhere

function:

>

stats:::coef.default

function (object, ...)
object$coefficients
<environment: namespace:stats>
>

getAnywhere(’coef.default’)

A single object matching ’coef.default’ was found
It was found in the following places

registered S3 method for coef from namespace stats
namespace:stats

with value
function (object, ...)
object$coefficients
<environment: namespace:stats>

There can be problems if you want to modify a function that is in a namespace.
Functions

assignInNamespace

and

unlockBinding

can be useful in this regard.

The existence of namespaces, S3 methods, and especially S4 methods makes

R more suitable to large, complex applications than it would otherwise be. But
R is not the best tool for every application. And it doesn’t try to be. One of the
design goals of R is to make it easy to interact with other software to encourage
the best tool being used for each task.

43


background image

Circle 8

Believing It Does as
Intended

In this Circle we came across the fraudulent—each trapped in their own flame.

This Circle is wider and deeper than one might hope. Reasons for this

include:

Backwards compatibility. There is roughly a two-decade history of com-
patibility to worry about. If you are a new user, you will think that rough
spots should be smoothed out no matter what. You will think differ-
ently if a new version of R breaks your code that has been working. The
larger splinters have been sanded down, but this still leaves a number of
annoyances to adjust to.

R is used both interactively and programmatically. There is tension there.
A few functions make special arrangements to make interactive use easier.
These functions tend to cause trouble if used inside a function. They can
also promote false expectations.

R does a lot.

In this Circle we will meet a large number of ghosts, chimeras and devils. These
can often be exorcised using the

browser

function. Put the command:

browser()

at strategic locations in your functions in order to see the state of play at those
points. A close alternative is:

recover()

44