Under most compilation environments, compiled code dynamically loaded into @R{} cannot have breakpoints set within it until it is loaded. To use a symbolic debugger on such dynamically loaded code under Unix-alikes use
dyn.load
or library
to load your
shared object.
Under Windows signals may not be able to be used, and if so the procedure is
more complicated. See the rw-FAQ and
www.stats.uwo.ca/faculty/murdoch/software/debuggingR/gdb.shtml
.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The key to inspecting @R{} objects from compiled code is the function
PrintValue(SEXP s)
which uses the normal @R{} printing
mechanisms to print the @R{} object pointed to by s, or the safer
version R_PV(SEXP s)
which will only print `objects'.
One way to make use of PrintValue
is to insert suitable calls
into the code to be debugged.
Another way is to call R_PV
from the symbolic debugger.
(PrintValue
is hidden as Rf_PrintValue
.) For example,
from gdb
we can use
(gdb) p R_PV(ab) |
using the object ab
from the convolution example, if we have
placed a suitable breakpoint in the convolution C code.
To examine an arbitrary @R{} object we need to work a little harder. For example, let
R> DF <- data.frame(a = 1:3, b = 4:6) |
By setting a breakpoint at do_get
and typing get("DF") at
the @R{} prompt, one can find out the address in memory of DF
, for
example
Value returned is $1 = (SEXPREC *) 0x40583e1c (gdb) p *$1 $2 = { sxpinfo = {type = 19, obj = 1, named = 1, gp = 0, mark = 0, debug = 0, trace = 0, = 0}, attrib = 0x40583e80, u = { vecsxp = { length = 2, type = {c = 0x40634700 "0>X@D>X@0>X@", i = 0x40634700, f = 0x40634700, z = 0x40634700, s = 0x40634700}, truelength =<PHONE_NUMBER>, }, primsxp = {offset = 2}, symsxp = {pname = 0x2, value = 0x40634700, internal = 0x40203008}, listsxp = {carval = 0x2, cdrval = 0x40634700, tagval = 0x40203008}, envsxp = {frame = 0x2, enclos = 0x40634700}, closxp = {formals = 0x2, body = 0x40634700, env = 0x40203008}, promsxp = {value = 0x2, expr = 0x40634700, env = 0x40203008} } } |
(Debugger output reformatted for better legibility).
Using R_PV()
one can "inspect" the values of the various
elements of the SEXP, for example,
(gdb) p R_PV($1->attrib) $names [1] "a" "b" $row.names [1] "1" "2" "3" $class [1] "data.frame" $3 = void |
To find out where exactly the corresponding information is stored, one needs to go "deeper":
(gdb) set $a = $1->attrib (gdb) p $a->u.listsxp.tagval->u.symsxp.pname->u.vecsxp.type.c $4 = 0x405d40e8 "names" (gdb) p $a->u.listsxp.carval->u.vecsxp.type.s[1]->u.vecsxp.type.c $5 = 0x40634378 "b" (gdb) p $1->u.vecsxp.type.s[0]->u.vecsxp.type.i[0] $6 = 1 (gdb) p $1->u.vecsxp.type.s[1]->u.vecsxp.type.i[1] $7 = 5 |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Access to operating system functions is via the @R{} function
system
.
The details will differ by platform (see the on-line help), and about
all that can safely be assumed is that the first argument will be a
string command
that will be passed for execution (not necessarily
by a shell) and the second argument will be internal
which if
true will collect the output of the command into an @R{} character
vector.
The function system.time
is available for timing (although the information available may be
limited on non-Unix-like platforms: these days only on the obsolete
Windows 9x/ME).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
.C
and .Fortran
These two functions provide a standard interface to compiled code that
has been linked into @R{}, either at build time or via dyn.load
(see section dyn.load
and dyn.unload
). They are primarily intended for
compiled C and FORTRAN 77 code respectively, but the .C
function can
be used with other languages which can generate C interfaces, for
example C++ (see section Interfacing C++ code).
The first argument to each function is a character string given the
symbol name as known to C or FORTRAN, that is the function or subroutine
name. (That the symbol is loaded can be tested by, for example,
is.loaded("cg")
: it is no longer necessary nor correct to use
symbol.For
, which is defunct as from @R{} 2.5.0.) (Note that the
underscore is not a valid character in a FORTRAN 77 subprogram name, and
on versions of @R{} prior to 2.4.0 .Fortran
may not correctly
translate names containing underscores.)
There can be up to 65 further arguments giving @R{} objects to be passed to compiled code. Normally these are copied before being passed in, and copied again to an @R{} list object when the compiled code returns. If the arguments are given names, these are used as names for the components in the returned list object (but not passed to the compiled code).
The following table gives the mapping between the modes of @R{} vectors and the types of arguments to a C function or FORTRAN subroutine.
@R{} storage mode
C type
FORTRAN type
logical
int *
INTEGER
integer
int *
INTEGER
double
double *
DOUBLE PRECISION
complex
Rcomplex *
DOUBLE COMPLEX
character
char **
CHARACTER*255
raw
unsigned char *
none
Do please note the first two. On the 64-bit Unix/Linux platforms,
long
is 64-bit whereas int
and INTEGER
are 32-bit.
Code ported from S-PLUS (which uses long *
for logical
and
integer
) will not work on all 64-bit platforms (although it may
appear to work on some). Note also that if your compiled code is a
mixture of C functions and FORTRAN subprograms the argument types must
match as given in the table above.
C type Rcomplex
is a structure with double
members
r
and i
defined in the header file `R_ext/Complex.h'
included by `R.h'. (On most platforms which have it, this is
compatible withe C99 double complex
type.) Only a single
character string can be passed to or from FORTRAN, and the success of
this is compiler-dependent. Other @R{} objects can be passed to
.C
, but it is better to use one of the other interfaces. An
exception is passing an @R{} function for use with call_R
,
when the object can be handled as void *
en route to
call_R
, but even there .Call
is to be preferred.
Similarly, passing an @R{} list as an argument to a C routine should be
done using the .Call
interface. If one does use the .C
function to pass a list as an argument, it is visible to the routine as
an array in C of SEXP
types (i.e., SEXP *
). The elements
of the array correspond directly to the elements of the @R{} list.
However, this array must be treated as read-only and one must not assign
values to its elements within the C routine -- doing so bypasses R's
memory management facilities and will corrupt the object and the R
session.
It is possible to pass numeric vectors of storage mode double
to
C as float *
or to FORTRAN as REAL
by setting the
attribute Csingle
, most conveniently by using the @R{} functions
as.single
, single
or mode
. This is intended only
to be used to aid interfacing to existing C or FORTRAN code.
Unless formal argument NAOK
is true, all the other arguments are
checked for missing values NA
and for the IEEE special
values NaN
, Inf
and -Inf
, and the presence of any
of these generates an error. If it is true, these values are passed
unchecked.
Argument DUP
can be used to suppress copying. It is dangerous:
see the on-line help for arguments against its use. It is not possible
to pass numeric vectors as float *
or REAL
if
DUP=FALSE
, and character vectors cannot be used.
Argument PACKAGE
confines the search for the symbol name to a
specific shared object (or use "base"
for code compiled into
@R{}). Its use is highly desirable, as there is no way to avoid two
package writers using the same symbol name, and such name clashes are
normally sufficient to cause @R{} to crash. (If it is not present and
the call is from the body of a function defined in a package with a
name space, the shared object loaded by the first (if any)
useDynLib
directive will be used.)
For .C
only you can specify an ENCODING
argument: this
requests that (unless DUP = FALSE
) character vectors be
re-encoded to the requested encoding before being passed in, and
re-encoded from the requested encoding when passed back. Note that
encoding names are not standardized, and not all @R{} builds support
re-encoding. (The argument is ignored with a warning if re-encoding is
not supported at all: @R{} code can test for this via
capabilities("iconv")
.) But this can be useful to allow code to
work in a UTF-8 locale by specifying ENCODING = "latin1"
.
Note that the compiled code should not return anything except through
its arguments: C functions should be of type void
and FORTRAN
subprograms should be subroutines.
To fix ideas, let us consider a very simple example which convolves two
finite sequences. (This is hard to do fast in interpreted @R{} code, but
easy in C code.) We could do this using .C
by
void convolve(double *a, int *na, double *b, int *nb, double *ab) { int i, j, nab = *na + *nb - 1; for(i = 0; i < nab; i++) ab[i] = 0.0; for(i = 0; i < *na; i++) for(j = 0; j < *nb; j++) ab[i + j] += a[i] * b[j]; } |
called from @R{} by
conv <- function(a, b) .C("convolve", as.double(a), as.integer(length(a)), as.double(b), as.integer(length(b)), ab = double(length(a) + length(b) - 1))$ab |
Note that we take care to coerce all the arguments to the correct @R{}
storage mode before calling .C
; mistakes in matching the types
can lead to wrong results or hard-to-catch errors.
Special care is needed in handling character
vector arguments in
C (or C++). Since only DUP = TRUE
is allowed, on entry the
contents of the elements are duplicated and assigned to the elements of
a char **
array, and on exit the elements of the C array are
copied to create new elements of a character vector. This means that
the contents of the character strings of the char **
array can be
changed, including to \0
to shorten the string, but the strings
cannot be lengthened. It is possible to allocate a new string
via R_alloc
and replace an entry in the char **
array by the new string. However, when character vectors are used other
than in a read-only way, the .Call
interface is much to be
preferred.
Passing character strings to FORTRAN code needs even more care, and should be avoided where possible. Only the first element of the character vector is passed in, as a fixed-length (255) character array. Up to 255 characters are passed back to a length-one character vector. How well this works (or even if it works at all) depends on the C and FORTRAN compilers on each platform.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
dyn.load
and dyn.unload
Compiled code to be used with @R{} is loaded as a shared object (Unix and MacOS X, see section Creating shared objects for more information) or DLL (Windows).
The shared object/DLL is loaded by dyn.load
and unloaded by
dyn.unload
. Unloading is not normally necessary, but it is
needed to allow the DLL to be re-built on some platforms, including
Windows.
The first argument to both functions is a character string giving the path to the object. Programmers should not assume a specific file extension for the object/DLL (such as `.so') but use a construction like
file.path(path1, path2, paste("mylib", .Platform$dynlib.ext, sep="")) |
for platform independence. On Unix-alike systems the path supplied to
dyn.load
can be an absolute path, one relative to the current
directory or, if it starts with `~', relative to the user's home
directory.
Loading is most often done via a call to library.dynam
in the .First.lib
function of a package. This has the form
library.dynam("libname", package, lib.loc) |
where libname
is the object/DLL name with the extension
omitted. Note that the first argument, chname
, should
not be package
since this will not work if the package
is installed under another name (as it will be with a versioned install).
Under some Unix-alike systems there is a choice of how the symbols are
resolved when the object is loaded, governed by the arguments
local
and now
. Only use these if really necessary: in
particular using now=FALSE
and then calling an unresolved symbol
will terminate @R{} unceremoniously.
@R{} provides a way of executing some code automatically when a object/DLL
is either loaded or unloaded. This can be used, for example, to
register native routines with @R{}'s dynamic symbol mechanism, initialize
some data in the native code, or initialize a third party library. On
loading a DLL, @R{} will look for a routine within that DLL named
R_init_lib
where lib is the name of the DLL file with
the extension removed. For example, in the command
library.dynam("mylib", package, lib.loc) |
R looks for the symbol named R_init_mylib
. Similarly, when
unloading the object, @R{} looks for a routine named
R_unload_lib
, e.g., R_unload_mylib
. In either case,
if the routine is present, @R{} will invoke it and pass it a single
argument describing the DLL. This is a value of type DllInfo
which is defined in the `Rdynload.h' file in the `R_ext'
directory.
The following example shows templates for the initialization and
unload routines for the mylib
DLL.
#include <R.h> #include <Rinternals.h> #include <R_ext/Rdynload.h> void R_init_mylib(DllInfo *info) { /* Register routines, allocate resources. */ } void R_unload_mylib(DllInfo *info) { /* Release resources. */ }
If a shared object/DLL is loaded more than once the most recent version
is used. More generally, if the same symbol name appears in several
libraries, the most recently loaded occurrence is used. The
PACKAGE
argument and registration (see the next section) provide
good ways to avoid any ambiguity in which occurrence is meant.
On Unix-alikes the paths used to resolve dynamically linked dependent
libraries are fixed (for security reasons) when the process is launched,
so dyn.load
will only look for such libraries in the locations
set by the `R' shell script (via `etc/ldpaths') and in
the OS-specific defaults.
Windows allows more control (and less security) over where dependent
DLLs are looked for. On all versions this includes the PATH
environment variable, but with lowest priority: note that it does not
include the directory from which the DLL was loaded. On XP and later it
is possible(22) to add a single path with quite high priority via the
DLLpath
argument to dyn.load
. This is (by default) used
by library.dynam
to include the package's `libs' directory
in the DLL search path.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
By `native' routine, we mean an entry point in compiled code.
In calls to .C
, .Call
, .Fortran
and
.External
, @R{} must locate the specified native routine by looking
in the appropriate shared object/DLL. By default, @R{} uses the operating
system-specific dynamic loader to lookup the symbol. Alternatively, the
author of the DLL can explicitly register routines with @R{} and use a
single, platform-independent mechanism for finding the routines in the
DLL. One can use this registration mechanism to provide additional
information about a routine, including the number and type of the
arguments, and also make it available to @R{} programmers under a different
name. In the future, registration may be used to implement a form of
"secure" or limited native access.
To register routines with @R{}, one calls the C routine
R_registerRoutines
. This is typically done when the DLL is first
loaded within the initialization routine R_init_dll name
described in dyn.load
and dyn.unload
. R_registerRoutines
takes 5 arguments. The first is the DllInfo
object passed by
@R{} to the initialization routine. This is where @R{} stores the
information about the methods. The remaining 4 arguments are arrays
describing the routines for each of the 4 different interfaces:
.C
, .Call
, .Fortran
and .External
. Each
argument is a NULL
-terminated array of the element types given in
the following table:
.C
R_CMethodDef
.Call
R_CallMethodDef
.Fortran
R_FortranMethodDef
.External
R_ExternalMethodDef
Currently, the R_ExternalMethodDef
is the same as
R_CallMethodDef
type and contains fields for the name of the
routine by which it can be accessed in @R{}, a pointer to the actual native
symbol (i.e., the routine itself), and the number of arguments the
routine expects. For routines with a variable number of arguments
invoked via the .External
interface, one specifies -1
for
the number of arguments which tells @R{} not to check the actual number
passed. For example, if we had a routine named myCall
defined as
SEXP myCall(SEXP a, SEXP b, SEXP c); |
we would describe this as
R_CallMethodDef callMethods[] = { {"myCall", &myCall, 3}, {NULL, NULL, 0} }; |
along with any other routines for the .Call
interface.
Routines for use with the .C
and .Fortran
interfaces are
described with similar data structures, but which have two additional
fields for describing the type and "style" of each argument. Each of
these can be omitted. However, if specified, each should be an array
with the same number of elements as the number of parameters for the
routine. The types array should contain the SEXP
types
describing the expected type of the argument. (Technically, the elements
of the types array are of type R_NativePrimitiveArgType
which is
just an unsigned integer.) The @R{} types and corresponding type
identifiers are provided in the following table:
numeric
REALSXP
integer
INTSXP
logical
LGLSXP
single
SINGLESXP
character
STRSXP
list
VECSXP
Consider a C routine, myC
, declared as
void myC(double *x, int *n, char **names, int *status); |
We would register it as
R_CMethodDef cMethods[] = { {"myC", &myC, 4, {REALSXP, INTSXP, STRSXP, LGLSXP}}, {NULL, NULL, 0} }; |
One can also specify whether each argument is used simply as input, or as output, or as both input and output. The style field in the description of a method is used for this. The purpose is to allow @R{} to transfer values more efficiently across the R-C/FORTRAN interface by avoiding copying values when it is not necessary. Typically, one omits this information in the registration data.
Having created the arrays describing each routine, the last step is to
actually register them with @R{}. We do this by calling
R_registerRoutines
. For example, if we have the descriptions
above for the routines accessed by the .C
and .Call
we would use the following code:
void R_init_myLib(DllInfo *info) { R_registerRoutines(info, cMethods, callMethods, NULL, NULL); } |
This routine will be invoked when @R{} loads the shared object/DLL named
myLib
. The last two arguments in the call to
R_registerRoutines
are for the routines accessed by
.Fortran
and .External
interfaces. In our example, these
are given as NULL
since we have no routines of these types.
When @R{} unloads a shared object/DLL, any registered routines are automatically removed. There is no (direct) facility for unregistering a symbol.
Examples of registering routines can be found in the different packages in the @R{} source tree (e.g., @pkg{stats}). Also, there is a brief, high-level introduction in R News (volume 1/3, September 2001, pages 20-23).
In addition to registering C routines to be called by @R{}, it can at times be useful for one package to make some of its C routines available to be called by C code in another package. An interface to support this has been provided since @R{} 2.4.0. The interface consists of two routines declared as
void R_RegisterCCallable(const char *package, const char *name, DL_FUNC fptr); DL_FUNC R_GetCCallable(const char *package, const char *name); |
A package @pkg{packA} that wants to make a C routine myCfun
available to C code in other packages would include the call
R_RegisterCCallable("packA", "myCfun", myCfun); |
in its initialization function R_init_packA
. A package
@pkg{packB} that wants to use this routine would retrieve the function
pointer with a call of the form
p_myCfun = R_GetCCallable("packA", "myCfun"); |
The author of @pkg{packB} is responsible for ensuring that
p_myCfun
has an appropriate declaration. In the future @R{} may
provide some automated tools to simplify exporting larger numbers of
routines.
A package that wishes to make use of header files in other packages needs
to declare them as a comma-separated list in the field LinkingTo
in the `DESCRIPTION' file. For example
Depends: link2, link3 LinkingTo: link2, link3 |
It should also `Depend' on those packages for they have to be installed prior to this one, and loaded prior to this one (so the path to their compiled code can be found).
This then arranges that the `include' directories in the installed linked-to packages are added to the include paths for C and C++ code.
A CRAN example of the use of this mechanism is package @pkg{lme4}, which links to @pkg{Matrix}.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Shared objects for loading into @R{} can be created using R CMD
SHLIB
. This accepts as arguments a list of files which must be object
files (with extension `.o') or sources for C, C++, FORTRAN 77,
Fortran 9x, Objective C or Objective C++ (with extensions `.c',
`.cc' or `.cpp' or `.C', `.f', `.f90' or
`.f95', `.m', and `.mm' or `.M', respectively), or
commands to be passed to the linker. See R CMD SHLIB --help (or
the @R{} help for SHLIB
) for usage information.
If compiling the source files does not work "out of the box", you can
specify additional flags by setting some of the variables
PKG_CPPFLAGS
(for the C preprocessor, typically `-I' flags),
PKG_CFLAGS
, PKG_CXXFLAGS
, PKG_FFLAGS
,
PKG_FCFLAGS
, and PKG_OBJCFLAGS
(for the C, C++, FORTRAN
77, Fortran 9x, and Objective C compilers, respectively) in the file
`Makevars' in the compilation directory (or, of course, create the
object files directly from the command line).
Similarly, variable PKG_LIBS
in `Makevars' can be used for
additional `-l' and `-L' flags to be passed to the linker when
building the shared object. (Supplying linker commands as arguments to
R CMD SHLIB
will override PKG_LIBS
in `Makevars'.)
It is possible to arrange to include compiled code from other languages by setting the macro `OBJECTS' in file `Makevars', together with suitable rules to make the objects.
Flags which are already set (for example in file
`etcR_ARCH/Makeconf' on Unix-alikes) can be overridden by the
environment variable MAKEFLAGS
(at least for systems using a
POSIX-compliant make
), as in (Bourne shell syntax)
MAKEFLAGS="CFLAGS=-O3" R CMD SHLIB *.c |
It is also possible to set such variables in personal `Makevars' files, which are read after the local `Makevars' and the system makefiles.
Note that as R CMD SHLIB
uses Make, it will not remake a shared
object just because the flags have changed, and if `test.c' and
`test.f' both exist in the current directory
R CMD SHLIB test.f |
will compile `test.c'!
If the `src' subdirectory of an add-on package contains source code
with one of the extensions listed above or a file `Makevars' but
not a file Makefile
, R CMD INSTALL
creates a
shared object (for loading into @R{} in the .First.lib
or
.onLoad
function of the package) using the R CMD SHLIB
mechanism. If file `Makevars' exists it is read first, then the
system makefile and then any personal `Makevars' files.
If the `src' subdirectory of package contains a file
`Makefile', this is used in place of the R CMD SHLIB
mechanism. make
is called with makefiles
`R_HOME/etcR_ARCH/Makeconf'(23), `src/Makefile' and any personal
`Makevars' files (in that order). The first target found in
`src/Makefile' is used.
It is better to make use of a Makevars
file rather than a Makefile
: the latter should be needed only
exceptionally.
Note that whereas R CMD INSTALL
makes use of a `Makefile',
R CMD SHLIB
does not. The file must be named `Makefile',
not for example `makefile' nor `GNUmakefile'.
Under Windows(24) the same commands
work, but `Makevars.win' will be used in preference to
`Makevars', and only `src/Makefile.win' will be used by
R CMD INSTALL
with `src/Makefile' being ignored. For
details of building DLLs with a variety of compilers, see file
`README.packages' and
http://www.stats.uwo.ca/faculty/murdoch/software/compilingDLLs/
.
Under Windows you can supply an exports file called
`dllname-win.def': otherwise all entry points in objects (but
not libraries) supplied to R CMD SHLIB
will be exported from the
DLL. An example is `stats-win.def' for the @pkg{stats} package.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Suppose we have the following hypothetical C++ library, consisting of
the two files `X.hh' and `X.cc', and implementing the two
classes X
and Y
which we want to use in @R{}.
// X.hh class X { public: X (); ~X (); }; class Y { public: Y (); ~Y (); };
// X.cc #include <iostream> #include "X.hh" static Y y; X::X() { std::cout << "constructor X" << std::endl; } X::~X() { std::cout << "destructor X" << std::endl; } Y::Y() { std::cout << "constructor Y" << std::endl; } Y::~Y() { std::cout << "destructor Y" << std::endl; }
To use with @R{}, the only thing we have to do is writing a wrapper function and ensuring that the function is enclosed in
extern "C" { } |
For example,
// X_main.cc: #include "X.hh" extern "C" { void X_main () { X x; } } // extern "C"
Compiling and linking should be done with the C++ compiler-linker
(rather than the C compiler-linker or the linker itself); otherwise, the
C++ initialization code (and hence the constructor of the static
variable Y
) are not called. On a properly configured system, one
can simply use
R CMD SHLIB X.cc X_main.cc |
to create the shared object, typically `X.so' (the file name extension may be different on your platform). Now starting @R{} yields
R : Copyright 2000, The R Development Core Team Version 1.1.0 Under development (unstable) (April 14, 2000) ... Type "q()" to quit R. R> dyn.load(paste("X", .Platform$dynlib.ext, sep = "")) constructor Y R> .C("X_main") constructor X destructor X list() R> q() Save workspace image? [y/n/c]: y destructor Y |
The @R{} for Windows FAQ (`rw-FAQ') contains details of how to compile this example under various Windows compilers.
Using C++ iostreams, as in this example, is best avoided. There is no guarantee that the output will appear in the @R{} console, and indeed it will not on the @R{} for Windows console. Use @R{} code or the C entry points (see section Printing) for all I/O if at all possible.
Most @R{} header files can be included within C++ programs, and they
should not be included within an extern "C"
block (as
they include C++ system headers). It may not be possible to include
some @R{} headers as they in turn include C header files that may cause
conflicts--if this happens, define `NO_C_HEADERS' before including
the @R{} headers, and include the appropriate headers yourself.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
We have already warned against the use of C++ iostreams not least
because output is not guaranteed to appear on the @R{} console, and this
warning applies equally to Fortran (77 or 9x) output to units *
and 6
. See section Printing from FORTRAN, which describes workarounds.
In the past most Fortran compilers implemented I/O on top of the C I/O
system and so the two interworked successfully. This was true of
g77
, but it is less true of gfortran
as used in
gcc 4.y.z
. In particular, any package that makes use of Fortran
I/O will when compiled on Windows interfere with C I/O: when the Fortran
I/O is initialized (typically when the package is loaded) the C
stdout
and stderr
are switched to LF line endings.
(Function La_Init
in file `src/main/lapack.c' shows how to
mitigate this.) Even worse, prior to @R{} 2.6.2 using Fortran output
when running under the Windows GUI console (Rgui
) would hang the
@R{} session. This is now avoided by ensuring that the Fortran output
is written to a file (`fort.6' in the working directory).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is not in general possible to link a DLL in package @pkg{packA} to a
DLL provided by package @pkg{packB} (for the security reasons mentioned
in dyn.load
and dyn.unload
, and also because some platforms
distinguish between shared and dynamic libraries), but it is on Windows.
Note that there can be tricky versioning issues here, as package @pkg{packB} could be re-installed after package @pkg{packA} -- it is desirable that the API provided by package @pkg{packB} remains backwards-compatible.
| 5.8.1 Unix-alikes | ||
| 5.8.2 Windows |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is possible to link a shared object in package @pkg{packA} to a library provided by package @pkg{packB} under limited circumstances on a Unix-alke OS. There are severe portability issues, so this is not recommended for a distributed package.
This is easiest if @pkg{packB} provides a static library
`packB/libs/libpackB.a'. (This will need to be comiled with
PIC
flags on platforms where it matters.) Then as the code from
package @pkg{packB} is incorporated when package @pkg{packA} is
installed, we only need to find the static library at install time for
package @pkg{packB}. The only issue is to find package @pkg{packB}, and
for that we can ask @R{} by something like
PKGB_PATH=`echo 'library(packB); cat(system.file("libs", package="packB"))' \ | R --vanilla --slave` PKG_LIBS=$(PKGB_PATH)/libpackB.a |
(If `libpackB.a' itself depends on other libraries these will need
to be included in PKG_LIBS
.)
For a dynamic library `packB/libs/libpackB.so' (`packB/libs/libpackB.dylib' on Mac OS X) we could use
PKGB_PATH=`echo 'library(packB); cat(system.file("libs", package="packB"))' \ | R --vanilla --slave` PKG_LIBS=-L"$(PKGB_PATH)" -lpackB |
This will work for installation, but very likely not when package
packB
is loaded, as the path to package @pkg{packB}'s `libs'
directory is not in the ld.so
(25) search path. You can
arrange to put it there before @R{} is launched by setting (on
some platforms) LD_RUN_PATH
or LD_LIBRARY_PATH
or adding to
the ld.so
cache (see ldconfig
). On platforms that
support it, the path to the dynamic library can be hardcoded at install
time (which assumes that the location of package @pkg{packB} will not be
changed). On systems with the GNU linker (e.g. Linux) and some others
(e.g. Mac OS X) this can be done by
PKGB_PATH=`echo 'library(packB); cat(system.file("libs", package="packB"))' \ | R --vanilla --slave` PKG_LIBS=-L"$(PKGB_PATH)" -rpath "$(PKGB_PATH)" -lpackB |
and on some other systems (e.g. Solaris with its native linker) use
-R
rather than -rpath
.
It may be possible to figure out what is required semi-automatically
from the result of R CMD libtool --config
(look for
`hardode').
Making headers provided by package @pkg{packB} available to the code to
be compiled in package @pkg{packA} can be done by the LinkingTo
mechanism (see section Registering native routines).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Suppose package @pkg{packA} wants to make use of compiled code provided by @pkg{packB} in DLL `packB/libs/exB.dll', possibly the package's DLL `packB/libs/packB.dll'. (This can be extended to linking to more than one package in a similar way.) There are three issues to be addressed:
This is done by the LinkingTo
mechanism (see section Registering native routines).
packA.dll
to link to `packB/libs/exB.dll'.
This needs an entry in `Makevars.win' of the form
PKG_LIBS= -L<something> -lexB |
and one possibility is that <something>
is the path to the
installed `pkgB/libs' directory. To find that we need to ask @R{}
where it is by something like
PKGB_PATH=`echo 'library(packB); cat(system.file("libs", package="packB"))' \ | rterm --vanilla --slave` PKG_LIBS= -L"$(PKGB_PATH)" -lexB |
Another possibility is to use an import library, shipping with package @pkg{packA} an exports file `exB.def'. Then `Makevars.win' could contain
PKG_LIBS= -L. -lexB before: libexB.dll.a libexB.dll.a: exB.def |
and then installing package @pkg{packA} will make and use the import library for `exB.dll'. (One way to prepare the exports file is to use `pexports.exe'.
If exB.dll
was used by package @pkg{packB} (because it is in fact
`packB.dll' or `packB.dll' depends on it) and @pkg{packB} has
been loaded before @pkg{packA}, then nothing more needs to be done as
`exB.dll' will already be loaded into the @R{} executable. (This
is the most common scenario).
More generally, we can use the DLLpath
argument to
library.dynam
to ensure that exB.dll
is found, for example
by setting
library.dynam("packA", pkg, lib, DLLpath = system.file("libs", package="packB")) |
Note that DLLpath
can only set one path, and so for linking to
two or more packages you would need to resort to setting PATH
.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Using C code to speed up the execution of an @R{} function is often very
fruitful. Traditionally this has been done via the .C
function
in @R{}.
One restriction of this interface is that the @R{} objects can not be
handled directly in C. This becomes more troublesome when one wishes to
call @R{} functions from within the C code. There is a C function
provided called call_R
(also known as call_S
for
compatibility with S) that can do that, but it is cumbersome to use, and
the mechanisms documented here are usually simpler to use, as well as
more powerful.
If a user really wants to write C code using internal @R{} data
structures, then that can be done using the .Call
and
.External
function. The syntax for the calling function in @R{}
in each case is similar to that of .C
, but the two functions have
different C interfaces. Generally the .Call
interface (which is
modelled on the interface of the same name in @Sl{} version 4) is a
little simpler to use, but .External
is a little more general.
A call to .Call
is very similar to .C
, for example
.Call("convolve2", a, b) |
The first argument should be a character string giving a C symbol name of code that has already been loaded into @R{}. Up to 65 @R{} objects can passed as arguments. The C side of the interface is
#include <R.h> #include <Rinternals.h> SEXP convolve2(SEXP a, SEXP b) ... |
A call to .External
is almost identical
.External("convolveE", a, b) |
but the C side of the interface is different, having only one argument
#include <R.h> #include <Rinternals.h> SEXP convolveE(SEXP args) ... |
Here args
is a LISTSXP
, a Lisp-style pairlist from which
the arguments can be extracted.
In each case the @R{} objects are available for manipulation via a set
of functions and macros defined in the header file `Rinternals.h'
or some S4-compatibility macros defined in `Rdefines.h'. See
Interface functions .Call
and .External
for details on
.Call
and .External
.
 First, consider working in interpreted @R{}
code; if this is fast enough, this is normally the best option. You
should also see if using .C
is enough. If the task to be
performed in C is simple enough requiring no call to @R{}, .C
suffices. The new interfaces are relatively recent additions to @Sl{}
and @R{}, and a great deal of useful code has been written using just
.C
before they were available. The .Call
and
.External
interfaces allow much more control, but they also
impose much greater responsibilities so need to be used with care.
Neither .Call
nor .External
copy their arguments. You
should treat arguments you receive through these interfaces as
read-only.
There are two approaches that can be taken to handling @R{} objects from
within C code. The first (historically) is to use the macros and
functions that have been used to implement the core parts of @R{}
through .Internal
calls. A public(26) subset of these is
defined in the header file `Rinternals.h' in the directory
`R_INCLUDE_DIR' (default `R_HOME/include') that
should be available on any @R{} installation.
Another approach is to use @R{} versions of the macros and functions
defined for the @Sl{} version 4 interface .Call
, which are
defined in the header file `Rdefines.h'. This is a somewhat
simpler approach, and is to be preferred if the code is intended to be
shared with @Sl{}. However, it is less well documented and even less
tested. Note too that some idiomatic S4 constructions with these macros
(such as assigning elements of character vectors or lists) are invalid
in @R{}.
A substantial amount of @R{} is implemented using the functions and macros described here, so the @R{} source code provides a rich source of examples and "how to do it": indeed many of the examples here were developed by examining closely @R{} system functions for similar tasks. Do make use of the source code for inspirational examples.
It is necessary to know something about how @R{} objects are handled in
C code. All the @R{} objects you will deal with will be handled with
the type SEXP(27), which is a
pointer to a structure with typedef SEXPREC
. Think of this
structure as a variant type that can handle all the usual types
of @R{} objects, that is vectors of various modes, functions,
environments, language objects and so on. The details are given later
in this section and in (R-ints)R Internal Structures section `R Internal Structures' in R Internals, but for most
purposes the programmer does not need to know them. Think rather of a
model such as that used by Visual Basic, in which @R{} objects are
handed around in C code (as they are in interpreted @R{} code) as the
variant type, and the appropriate part is extracted for, for example,
numerical calculations, only when it is needed. As in interpreted @R{}
code, much use is made of coercion to force the variant object to the
right type.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
We need to know a little about the way @R{} handles memory allocation. The memory allocated for @R{} objects is not freed by the user; instead, the memory is from time to time garbage collected. That is, some or all of the allocated memory not being used is freed.
The @R{} object types are represented by a C structure defined by a
typedef SEXPREC
in `Rinternals.h'. It contains several
things among which are pointers to data blocks and to other
SEXPREC
s. A SEXP
is simply a pointer to a SEXPREC
.
If you create an @R{} object in your C code, you must tell @R{} that you
are using the object by using the PROTECT
macro on a pointer to
the object. This tells @R{} that the object is in use so it is not
destroyed during garbage collection. Notice that it is the object which
is protected, not the pointer variable. It is a common mistake to
believe that if you invoked PROTECT(p)
at some point then
p is protected from then on, but that is not true once a new
object is assigned to p.
Protecting an @R{} object automatically protects all the @R{} objects
pointed to in the corresponding SEXPREC
, for example all elements
of a protected list are automatically protected.
The programmer is solely responsible for housekeeping the calls to
PROTECT
. There is a corresponding macro UNPROTECT
that
takes as argument an int
giving the number of objects to
unprotect when they are no longer needed. The protection mechanism is
stack-based, so UNPROTECT(n)
unprotects the last n
objects which were protected. The calls to PROTECT
and
UNPROTECT
must balance when the user's code returns. @R{} will
warn about "stack imbalance in .Call"
(or .External
) if
the housekeeping is wrong.
Here is a small example of creating an @R{} numeric vector in C code. First we use the macros in `Rinternals.h':
#include <R.h> #include <Rinternals.h> SEXP ab; .... PROTECT(ab = allocVector(REALSXP, 2)); REAL(ab)[0] = 123.45; REAL(ab)[1] = 67.89; UNPROTECT(1); |
and then those in `Rdefines.h':
#include <R.h> #include <Rdefines.h> SEXP ab; .... PROTECT(ab = NEW_NUMERIC(2)); NUMERIC_POINTER(ab)[0] = 123.45; NUMERIC_POINTER(ab)[1] = 67.89; UNPROTECT(1); |
Now, the reader may ask how the @R{} object could possibly get removed
during those manipulations, as it is just our C code that is running.
As it happens, we can do without the protection in this example, but in
general we do not know (nor want to know) what is hiding behind the @R{}
macros and functions we use, and any of them might cause memory to be
allocated, hence garbage collection and hence our object ab
to be
removed. It is usually wise to err on the side of caution and assume
that any of the @R{} macros and functions might remove the object.
In some cases it is necessary to keep better track of whether protection
is really needed. Be particularly aware of situations where a large
number of objects are generated. The pointer protection stack has a
fixed size (default 10,000) and can become full. It is not a good idea
then to just PROTECT
everything in sight and UNPROTECT
several thousand objects at the end. It will almost invariably be
possible to either assign the objects as part of another object (which
automatically protects them) or unprotect them immediately after use.
Protection is not needed for objects which @R{} already knows are in use. In particular, this applies to function arguments.
There is a less-used macro UNPROTECT_PTR(s)
that unprotects
the object pointed to by the SEXP
s, even if it is not the
top item on the pointer protection stack. This is rarely needed outside
the parser (the @R{} sources have one example, in
`src/main/plot3d.c').
Sometimes an object is changed (for example duplicated, coerced or
grown) yet the current value needs to be protected. For these cases
PROTECT_WITH_INDEX
saves an index of the protection location that
can be used to replace the protected value using REPROTECT
.
For example (from the internal code for optim
)
PROTECT_INDEX ipx; .... PROTECT_WITH_INDEX(s = eval(OS->R_fcall, OS->R_env), &ipx); REPROTECT(s = coerceVector(s, REALSXP), ipx); |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
For many purposes it is sufficient to allocate @R{} objects and
manipulate those. There are quite a few allocXxx
functions
defined in `Rinternals.h'--you may want to explore them. These
allocate @R{} objects of various types, and for the standard vector
types there are equivalent NEW_XXX
macros defined in
`Rdefines.h'.
If storage is required for C objects during the calculations this is
best allocating by calling R_alloc
; see section Memory allocation.
All of these memory allocation routines do their own error-checking, so
the programmer may assume that they will raise an error and not return
if the memory cannot be allocated.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Users of the `Rinternals.h' macros will need to know how the @R{} types are known internally: if the `Rdefines.h' macros are used then S4-compatible names are used.
The different @R{} data types are represented in C by SEXPTYPE. Some of these are familiar from @R{} and some are internal data types. The usual @R{} object modes are given in the table.
SEXPTYPE
@R{} equivalent
REALSXP
numeric with storage mode
double
INTSXP
integer
CPLXSXP
complex
LGLSXP
logical
STRSXP
character
VECSXP
list (generic vector)
LISTSXP
"dotted-pair" list
DOTSXP
a `…' object
NILSXP
NULL
SYMSXP
name/symbol
CLOSXP
function or function closure
ENVSXP
environment
Among the important internal SEXPTYPE
s are LANGSXP
,
CHARSXP
, PROMSXP
, etc. (Note: although it is
possible to return objects of internal types, it is unsafe to do so as
assumptions are made about how they are handled which may be violated at
user-level evaluation.) More details are given in (R-ints)R Internal Structures section `R Internal Structures' in R Internals.
Unless you are very sure about the type of the arguments, the code
should check the data types. Sometimes it may also be necessary to
check data types of objects created by evaluating an @R{} expression in
the C code. You can use functions like isReal
, isInteger
and isString
to do type checking. See the header file
`Rinternals.h' for definitions of other such functions. All of
these take a SEXP
as argument and return 1 or 0 to indicate
TRUE or FALSE. Once again there are two ways to do this,
and `Rdefines.h' has macros such as IS_NUMERIC
.
What happens if the SEXP
is not of the correct type? Sometimes
you have no other option except to generate an error. You can use the
function error
for this. It is usually better to coerce the
object to the correct type. For example, if you find that an
SEXP
is of the type INTEGER
, but you need a REAL
object, you can change the type by using, equivalently,
PROTECT(newSexp = coerceVector(oldSexp, REALSXP)); |
or
PROTECT(newSexp = AS_NUMERIC(oldSexp)); |
Protection is needed as a new object is created; the object
formerly pointed to by the SEXP
is still protected but now
unused.
All the coercion functions do their own error-checking, and generate
NA
s with a warning or stop with an error as appropriate.
Note that these coercion functions are not the same as calling
as.numeric
(and so on) in @R{} code, as they do not dispatch on
the class of the object. Thus it is normally preferable to do the
coercion in the calling @R{} code.
So far we have only seen how to create and coerce @R{} objects from C code, and how to extract the numeric data from numeric @R{} vectors. These can suffice to take us a long way in interfacing @R{} objects to numerical algorithms, but we may need to know a little more to create useful return objects.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Many @R{} objects have attributes: some of the most useful are classes
and the dim
and dimnames
that mark objects as matrices or
arrays. It can also be helpful to work with the names
attribute
of vectors.
To illustrate this, let us write code to take the outer product of two
vectors (which outer
and %o%
already do). As usual the
@R{} code is simple
out <- function(x, y) { storage.mode(x) <- storage.mode(y) <- "double" .Call("out", x, y) } |
where we expect x
and y
to be numeric vectors (possibly
integer), possibly with names. This time we do the coercion in the
calling @R{} code.
C code to do the computations is
#include <R.h> #include <Rinternals.h> SEXP out(SEXP x, SEXP y) { int i, j, nx, ny; double tmp, *rx = REAL(x), *ry = REAL(y), *rans; SEXP ans; nx = length(x); ny = length(y); PROTECT(ans = allocMatrix(REALSXP, nx, ny)); rans = REAL(ans); for(i = 0; i < nx; i++) { tmp = rx[i]; for(j = 0; j < ny; j++) rans[i + nx*j] = tmp * ry[j]; } UNPROTECT(1); return(ans); } |
Note the way REAL
is used: as it is a function call it can be
considerably faster to store the result and index that.
However, we would like to set the dimnames
of the result.
Although allocMatrix
provides a short cut, we will show how to
set the dim
attribute directly.
#include <R.h> #include <Rinternals.h> SEXP out(SEXP x, SEXP y) { R_len_t i, j, nx, ny; double tmp, *rx = REAL(x), *ry = REAL(y), *rans; SEXP ans, dim, dimnames; nx = length(x); ny = length(y); PROTECT(ans = allocVector(REALSXP, nx*ny)); rans = REAL(ans); for(i = 0; i < nx; i++) { tmp = rx[i]; for(j = 0; j < ny; j++) rans[i + nx*j] = tmp * ry[j]; } PROTECT(dim = allocVector(INTSXP, 2)); INTEGER(dim)[0] = nx; INTEGER(dim)[1] = ny; setAttrib(ans, R_DimSymbol, dim); PROTECT(dimnames = allocVector(VECSXP, 2)); SET_VECTOR_ELT(dimnames, 0, getAttrib(x, R_NamesSymbol)); SET_VECTOR_ELT(dimnames, 1, getAttrib(y, R_NamesSymbol)); setAttrib(ans, R_DimNamesSymbol, dimnames); UNPROTECT(3); return(ans); } |
This example introduces several new features. The getAttrib
and
setAttrib
functions get and set individual attributes. Their second argument is a
SEXP
defining the name in the symbol table of the attribute we
want; these and many such symbols are defined in the header file
`Rinternals.h'.
There are shortcuts here too: the functions namesgets
,
dimgets
and dimnamesgets
are the internal versions of the
default methods of names<-
, dim<-
and dimnames<-
(for vectors and arrays), and there are functions such as
GetMatrixDimnames
and GetArrayDimnames
.
What happens if we want to add an attribute that is not pre-defined? We
need to add a symbol for it via a call to
install
. Suppose for illustration we wanted to add an attribute
"version"
with value 3.0
. We could use
SEXP version; PROTECT(version = allocVector(REALSXP, 1)); REAL(version)[0] = 3.0; setAttrib(ans, install("version"), version); UNPROTECT(1); |
Using install
when it is not needed is harmless and provides a
simple way to retrieve the symbol from the symbol table if it is already
installed.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In @R{} the (S3) class is just the attribute named "class"
so it
can be handled as such, but there is a shortcut classgets
.
Suppose we want to give the return value in our example the class
"mat"
. We can use
#include <R.h> #include <Rdefines.h> .... SEXP ans, dim, dimnames, class; .... PROTECT(class = allocVector(STRSXP, 1)); SET_STRING_ELT(class, 0, mkChar("mat")); classgets(ans, class); UNPROTECT(4); return(ans); } |
As the value is a character vector, we have to know how to create that
from a C character array, which we do using the function
mkChar
.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Some care is needed with lists, as @R{} moved early on from using
LISP-like lists (now called "pairlists") to S-like generic vectors.
As a result, the appropriate test for an object of mode list
is
isNewList
, and we need allocVector(VECSXP, n
) and
not allocList(n)
.
List elements can be retrieved or set by direct access to the elements of the generic vector. Suppose we have a list object
a <- list(f=1, g=2, h=3) |
Then we can access a$g
as a[[2]]
by
double g; .... g = REAL(VECTOR_ELT(a, 1))[0]; |
This can rapidly become tedious, and the following function (based on one in package @pkg{stats}) is very useful:
/* get the list element named str, or return NULL */ SEXP getListElement(SEXP list, const char *str) { SEXP elmt = R_NilValue, names = getAttrib(list, R_NamesSymbol); int i; for (i = 0; i < length(list); i++) if(strcmp(CHAR(STRING_ELT(names, i)), str) == 0) { elmt = VECTOR_ELT(list, i); break; } return elmt; } |
and enables us to say
double g; g = REAL(getListElement(a, "g"))[0]; |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
R character vectors are stored as STRSXP
s, a vector type like
VECSXP
where every element is of type CHARSXP
. The
CHARSXP
elements of STRSXP
s are accessed using
STRING_ELT
and SET_STRING_ELT
.
As of @R{} 2.6.0, CHARSXP
s are read-only objects and must never
be modified. In particular, the C-style string contained in a
CHARSXP
should be treated as read-only and for this reason the
CHAR
function used to access the character data of a
CHARSXP
returns (const char *)
(this also allows compilers
to issue warnings about improper use). Since CHARSXP
s are
immutable, the same CHARSXP
can be shared by any STRSXP
needing an element representing the same string. As of @R{} 2.6.0, @R{}
maintains a global cache of CHARSXP
s so that there is only ever
one CHARSXP
representing a given string in memory.
You can obtain a CHARSXP
by calling mkChar
and providing a
nul-terminated C-style string. This function will return a pre-existing
CHARSXP
if one with a matching string already exists, otherwise
it will create a new one and add it to the cache before returning it to
you. The variant mkCharLen
can be used to create a
CHARSXP
from part of a buffer and will ensure null-termination.
Currently, it is still possible to create CHARSXP
s using
allocVector
; CHARSXP
s created in this way will not be
captured by the global CHARSXP
cache and this should be avoided.
In the future, all CHARSXP
s will be captured by the cache and
this will allow further optimizations, for example, replacing calls to
strcmp
with pointer comparisons. A helper macro,
CallocCharBuf
, can be used to obtain a temporary character buffer
for in-place string manipulation: this memory must be released using
Free
.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It will be usual that all the @R{} objects needed in our C computations
are passed as arguments to .Call
or .External
, but it is
possible to find the values of @R{} objects from within the C given
their names. The following code is the equivalent of get(name,
envir = rho)
.
SEXP getvar(SEXP name, SEXP rho) { SEXP ans; if(!isString(name) || length(name) != 1) error("name is not a single string"); if(!isEnvironment(rho)) error("rho should be an environment"); ans = findVar(install(CHAR(STRING_ELT(name, 0))), rho); printf("first value is %f\n", REAL(ans)[0]); return(R_NilValue); } |
The main work is done by
findVar
, but to use it we need to install name
as a name
in the symbol table. As we wanted the value for internal use, we return
NULL
.
Similar functions with syntax
void defineVar(SEXP symbol, SEXP value, SEXP rho) void setVar(SEXP symbol, SEXP value, SEXP rho) |
can be used to assign values to @R{} variables. defineVar
creates a new binding or changes the value of an existing binding in the
specified environment frame; it is the analogue of assign(symbol,
value, envir = rho, inherits = FALSE)
, but unlike assign
,
defineVar
does not make a copy of the object
value
.(28) setVar
searches for an existing
binding for symbol
in rho
or its enclosing environments.
If a binding is found, its value is changed to value
. Otherwise,
a new binding with the specified value is created in the global
environment. This corresponds to assign(symbol, value, envir =
rho, inherits = TRUE)
.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Some operations are done so frequently that there are convenience
functions to handle them. Suppose we wanted to pass a single logical
argument ignore_quotes
: we could use
int ign; ign = asLogical(ignore_quotes); if(ign == NA_LOGICAL) error("'ignore_quotes' must be TRUE or FALSE"); |
which will do any coercion needed (at least from a vector argument), and
return NA_LOGICAL
if the value passed was NA
or coercion
failed. There are also asInteger
, asReal
and
asComplex
. The function asChar
returns a CHARSXP
.
All of these functions ignore any elements of an input vector after the
first.
To return a length-one real vector we can use
double x; ... return ScalarReal(x); |
and there are versions of this for all the atomic vector types (those for
a length-one character vector being ScalarString
with argument a
CHARSXP
and mkString
with argument const char *
).
Some of the isXXXX
functions differ from their apparent
@R{}-level counterparts: for example isVector
is true for any
atomic vector type (isVectorAtomic
) and for lists and expressions
(isVectorList
) (with no check on attributes). isMatrix
is
a test of a length-2 "dim"
attribute.
There are a series of small macros/functions to help construct pairlists
and language objects (whose internal structures just differ by
SEXPTYPE
. Function CONS(u, v)
is the basic building
block: is constructs a pairlist from u
followed by v
(which is a pairlist or R_NilValue
). LCONS
is a variant
that constructs a language object. Functions list1
to
list4
construct a pairlist from one to four items, and
lang1
to lang4
do the same for a language object (a
function to call plus zero to three arguments). Function elt
and
lastElt
find the ith element and the last element of a
pairlist, and nthcdr
returns a pointer to the nth position
in the pairlist (whose CAR
is the nth item).
Functions str2type
and type2str
map @R{}
length-one character strings to and from SEXPTYPE
numbers, and
type2char
maps numbers to C character strings.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When assignments are done in @R{} such as
x <- 1:10 y <- x |
the named object is not necessarily copied, so after those two
assignments y
and x
are bound to the same SEXPREC
(the structure a SEXP
points to). This means that any code which
alters one of them has to make a copy before modifying the copy if the
usual @R{} semantics are to apply. Note that whereas .C
and
.Fortran
do copy their arguments (unless the dangerous dup
= FALSE
is used), .Call
and .External
do not. So
duplicate
is commonly called on arguments to .Call
before
modifying them.
However, at least some of this copying is unneeded. In the first
assignment shown, x <- 1:10
, @R{} first creates an object with
value 1:10
and then assigns it to x
but if x
is
modified no copy is necessary as the temporary object with value
1:10
cannot be referred to again. @R{} distinguishes between
named and unnamed objects via a field in a SEXPREC
that
can be accessed via the macros NAMED
and SET_NAMED
. This
can take values
0
The object is not bound to any symbol
1
The object has been bound to exactly one symbol
2
The object has potentially been bound to two or more symbols, and one should act as if another variable is currently bound to this value.
Note the past tenses: @R{} does not do full reference counting and there may currently be fewer bindings.
It is safe to modify the value of any SEXP
for which
NAMED(foo)
is zero, and if NAMED(foo)
is two, the value
should be duplicated (via a call to duplicate
) before any
modification. Note that it is the responsibility of the author of the
code making the modification to do the duplication, even if it is
x
whose value is being modified after y <- x
.
The case NAMED(foo) == 1
allows some optimization, but it can be
ignored (and duplication done whenever NAMED(foo) > 0
). (This
optimization is not currently usable in user code.) It is intended
for use within assignment functions. Suppose we used
x <- 1:10 foo(x) <- 3 |
which is computed as
x <- 1:10 x <- "foo<-"(x, 3) |
Then inside "foo<-"
the object pointing to the current value of
x
will have NAMED(foo)
as one, and it would be safe to
modify it as the only symbol bound to it is x
and that will be
rebound immediately. (Provided the remaining code in "foo<-"
make no reference to x
, and no one is going to attempt a direct
call such as y <- "foo<-"(x)
.)
Currently all arguments to a .Call
call will have NAMED
set to 2, and so users must assume that they need to be duplicated
before alteration.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
.Call
and .External
In this section we consider the details of the @R{}/C interfaces.
These two interfaces have almost the same functionality. .Call
is
based on the interface of the same name in @Sl{} version 4, and
.External
is based on .Internal
. .External
is more
complex but allows a variable number of arguments.
5.10.1 Calling .Call | ||
5.10.2 Calling .External | ||
| 5.10.3 Missing and special values |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
.Call
Let us convert our finite convolution example to use .Call
, first
using the `Rdefines.h' macros. The calling function in @R{} is
conv <- function(a, b) .Call("convolve2", a, b) |
which could hardly be simpler, but as we shall see all the type checking must be transferred to the C code, which is
#include <R.h> #include <Rdefines.h> SEXP convolve2(SEXP a, SEXP b) { int i, j, na, nb, nab; double *xa, *xb, *xab; SEXP ab; PROTECT(a = AS_NUMERIC(a)); PROTECT(b = AS_NUMERIC(b)); na = LENGTH(a); nb = LENGTH(b); nab = na + nb - 1; PROTECT(ab = NEW_NUMERIC(nab)); xa = NUMERIC_POINTER(a); xb = NUMERIC_POINTER(b); xab = NUMERIC_POINTER(ab); for(i = 0; i < nab; i++) xab[i] = 0.0; for(i = 0; i < na; i++) for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j]; UNPROTECT(3); return(ab); } |
Note that unlike the macros in @Sl{} version 4, the @R{} versions of these macros do check that coercion can be done and raise an error if it fails. They will raise warnings if missing values are introduced by coercion. Although we illustrate doing the coercion in the C code here, it often is simpler to do the necessary coercions in the @R{} code.
Now for the version in @R{}-internal style. Only the C code changes.
#include <R.h> #include <Rinternals.h> SEXP convolve2(SEXP a, SEXP b) { R_len_t i, j, na, nb, nab; double *xa, *xb, *xab; SEXP ab; PROTECT(a = coerceVector(a, REALSXP)); PROTECT(b = coerceVector(b, REALSXP)); na = length(a); nb = length(b); nab = na + nb - 1; PROTECT(ab = allocVector(REALSXP, nab)); xa = REAL(a); xb = REAL(b); xab = REAL(ab); for(i = 0; i < nab; i++) xab[i] = 0.0; for(i = 0; i < na; i++) for(j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j]; UNPROTECT(3); return(ab); } |
This is called in exactly the same way.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
.External
We can use the same example to illustrate .External
. The @R{}
code changes only by replacing .Call
by .External
conv <- function(a, b) .External("convolveE", a, b) |
but the main change is how the arguments are passed to the C code, this time as a single SEXP. The only change to the C code is how we handle the arguments.
#include <R.h> #include <Rinternals.h> SEXP convolveE(SEXP args) { int i, j, na, nb, nab; double *xa, *xb, *xab; SEXP a, b, ab; PROTECT(a = coerceVector(CADR(args), REALSXP)); PROTECT(b = coerceVector(CADDR(args), REALSXP)); ... } |
Once again we do not need to protect the arguments, as in the @R{} side of the interface they are objects that are already in use. The macros
first = CADR(args); second = CADDR(args); third = CADDDR(args); fourth = CAD4R(args); |
provide convenient ways to access the first four arguments. More
generally we can use the
CDR
and CAR
macros as in
args = CDR(args); a = CAR(args); args = CDR(args); b = CAR(args); |
which clearly allows us to extract an unlimited number of arguments
(whereas .Call
has a limit, albeit at 65 not a small one).
More usefully, the .External
interface provides an easy way to
handle calls with a variable number of arguments, as length(args)
will give the number of arguments supplied (of which the first is
ignored). We may need to know the names (`tags') given to the actual
arguments, which we can by using the TAG
macro and using
something like the following example, that prints the names and the first
value of its arguments if they are vector types.
#include <R_ext/PrtUtil.h> SEXP showArgs(SEXP args) { int i, nargs; Rcomplex cpl; const char *name; SEXP el; args = CDR(args); /* skip 'name' */ for(i = 0; args != R_NilValue; i++, args = CDR(args)) { args = CDR(args); name = CHAR(PRINTNAME(TAG(args))); switch(TYPEOF(CAR(args))) { case REALSXP: Rprintf("[%d] '%s' %f\n", i+1, name, REAL(CAR(args))[0]); break; case LGLSXP: case INTSXP: Rprintf("[%d] '%s' %d\n", i+1, name, INTEGER(CAR(args))[0]); break; case CPLXSXP: cpl = COMPLEX(CAR(args))[0]; Rprintf("[%d] '%s' %f + %fi\n", i+1, name, cpl.r, cpl.i); break; case STRSXP: Rprintf("[%d] '%s' %s\n", i+1, name, CHAR(STRING_ELT(CAR(args), 0))); break; default: Rprintf("[%d] '%s' R type\n", i+1, name); } } return(R_NilValue); } |
This can be called by the wrapper function
showArgs <- function(...) .External("showArgs", ...) |
Note that this style of programming is convenient but not necessary, as an alternative style is
showArgs1 <- function(...) .Call("showArgs1", list(...)) |
The (very similar) C code is in the scripts.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
One piece of error-checking the .C
call does (unless NAOK
is true) is to check for missing (NA
) and IEEE special
values (Inf
, -Inf
and NaN
) and give an error if any
are found. With the .Call
interface these will be passed to our
code. In this example the special values are no problem, as
IEEE arithmetic will handle them correctly. In the current
implementation this is also true of NA
as it is a type of
NaN
, but it is unwise to rely on such details. Thus we will
re-write the code to handle NA
s using macros defined in
`R_exts/Arith.h' included by `R.h'.
The code changes are the same in any of the versions of convolve2
or convolveE
:
... for(i = 0; i < na; i++) for(j = 0; j < nb; j++) if(ISNA(xa[i]) || ISNA(xb[j]) || ISNA(xab[i + j])) xab[i + j] = NA_REAL; else xab[i + j] += xa[i] * xb[j]; ... |
Note that the ISNA
macro, and the similar macros ISNAN
(which checks for NaN
or NA
) and R_FINITE
(which is
false for NA
and all the special values), only apply to numeric
values of type double
. Missingness of integers, logicals and
character strings can be tested by equality to the constants
NA_INTEGER
, NA_LOGICAL
and NA_STRING
. These and
NA_REAL
can be used to set elements of @R{} vectors to NA
.
The constants R_NaN
, R_PosInf
, R_NegInf
and
R_NaReal
can be used to set double
s to the special values.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
We noted that the call_R
interface could be used to evaluate @R{}
expressions from C code, but the current interfaces are much more
convenient to use. The main function we will use is
SEXP eval(SEXP expr, SEXP rho); |
the equivalent of the interpreted @R{} code eval(expr, envir =
rho)
, although we can also make use of findVar
, defineVar
and findFun
(which restricts the search to functions).
To see how this might be applied, here is a simplified internal version
of lapply
for expressions, used as
a <- list(a = 1:5, b = rnorm(10), test = runif(100)) .Call("lapply", a, quote(sum(x)), new.env()) |
with C code
SEXP lapply(SEXP list, SEXP expr, SEXP rho) { R_len_t i, n = length(list); SEXP ans; if(!isNewList(list)) error("'list' must be a list"); if(!isEnvironment(rho)) error("'rho' should be an environment"); PROTECT(ans = allocVector(VECSXP, n)); for(i = 0; i < n; i++) { defineVar(install("x"), VECTOR_ELT(list, i), rho); SET_VECTOR_ELT(ans, i, eval(expr, rho)); } setAttrib(ans, R_NamesSymbol, getAttrib(list, R_NamesSymbol)); UNPROTECT(1); return(ans); } |
It would be closer to lapply
if we could pass in a function
rather than an expression. One way to do this is via interpreted
@R{} code as in the next example, but it is possible (if somewhat
obscure) to do this in C code. The following is based on the code in
`src/main/optimize.c'.
SEXP lapply2(SEXP list, SEXP fn, SEXP rho) { R_len_t i, n = length(list); SEXP R_fcall, ans; if(!isNewList(list)) error("'list' must be a list"); if(!isFunction(fn)) error("'fn' must be a function"); if(!isEnvironment(rho)) error("'rho' should be an environment"); PROTECT(R_fcall = lang2(fn, R_NilValue)); PROTECT(ans = allocVector(VECSXP, n)); for(i = 0; i < n; i++) { SETCADR(R_fcall, VECTOR_ELT(list, i)); SET_VECTOR_ELT(ans, i, eval(R_fcall, rho)); } setAttrib(ans, R_NamesSymbol, getAttrib(list, R_NamesSymbol)); UNPROTECT(2); return(ans); } |
used by
.Call("lapply2", a, sum, new.env()) |
Function lang2
creates an executable pairlist of two elements, but
this will only be clear to those with a knowledge of a LISP-like
language.
As a more comprehensive example of constructing an @R{} call in C code
and evaluating, consider the following fragment of
printAttributes
in `src/main/print.c'.
/* Need to construct a call to print(CAR(a), digits=digits) based on the R_print structure, then eval(call, env). See do_docall for the template for this sort of thing. */ SEXP s, t; PROTECT(t = s = allocList(3)); SET_TYPEOF(s, LANGSXP); SETCAR(t, install("print")); t = CDR(t); SETCAR(t, CAR(a)); t = CDR(t); SETCAR(t, ScalarInteger(digits)); SET_TAG(t, install("digits")); eval(s, env); UNPROTECT(1); |
At this point CAR(a)
is the @R{} object to be printed, the
current attribute. There are three steps: the call is constructed as
a pairlist of length 3, the list is filled in, and the expression
represented by the pairlist is evaluated.
A pairlist is quite distinct from a generic vector list, the only
user-visible form of list in @R{}. A pairlist is a linked list (with
CDR(t)
computing the next entry), with items (accessed by
CAR(t)
) and names or tags (set by SET_TAG
). In this call
there are to be three items, a symbol (pointing to the function to be
called) and two argument values, the first unnamed and the second named.
Setting the type to LANGSXP
makes this a call which can be evaluated.
| 5.11.1 Zero-finding | ||
| 5.11.2 Calculating numerical derivatives |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
In this section we re-work the example of call_S
in Becker,
Chambers & Wilks (1988) on finding a zero of a univariate function,
The @R{} code and an example are
zero <- function(f, guesses, tol = 1e-7) { f.check <- function(x) { x <- f(x) if(!is.numeric(x)) stop("Need a numeric result") as.double(x) } .Call("zero", body(f.check), as.double(guesses), as.double(tol), new.env()) } cube1 <- function(x) (x^2 + 1) * (x - 1.5) zero(cube1, c(0, 5)) |
where this time we do the coercion and error-checking in the @R{} code. The C code is
SEXP mkans(double x) { SEXP ans; PROTECT(ans = allocVector(REALSXP, 1)); REAL(ans)[0] = x; UNPROTECT(1); return ans; } double feval(double x, SEXP f, SEXP rho) { defineVar(install("x"), mkans(x), rho); return(REAL(eval(f, rho))[0]); } SEXP zero(SEXP f, SEXP guesses, SEXP stol, SEXP rho) { double x0 = REAL(guesses)[0], x1 = REAL(guesses)[1], tol = REAL(stol)[0]; double f0, f1, fc, xc; if(tol <= 0.0) error("non-positive tol value"); f0 = feval(x0, f, rho); f1 = feval(x1, f, rho); if(f0 == 0.0) return mkans(x0); if(f1 == 0.0) return mkans(x1); if(f0*f1 > 0.0) error("x[0] and x[1] have the same sign"); for(;;) { xc = 0.5*(x0+x1); if(fabs(x0-x1) < tol) return mkans(xc); fc = feval(xc, f, rho); if(fc == 0) return mkans(xc); if(f0*fc > 0.0) { x0 = xc; f0 = fc; } else { x1 = xc; f1 = fc; } } } |
The C code is essentially unchanged from the call_R
version, just
using a couple of functions to convert from double
to SEXP
and to evaluate f.check
.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
We will use a longer example (by Saikat DebRoy) to illustrate the use of
evaluation and .External
. This calculates numerical derivatives,
something that could be done as effectively in interpreted @R{} code but
may be needed as part of a larger C calculation.
An interpreted @R{} version and an example are
numeric.deriv <- function(expr, theta, rho=sys.frame(sys.parent())) { eps <- sqrt(.Machine$double.eps) ans <- eval(substitute(expr), rho) grad <- matrix(,length(ans), length(theta), dimnames=list(NULL, theta)) for (i in seq(along=theta)) { old <- get(theta[i], envir=rho) delta <- eps * min(1, abs(old)) assign(theta[i], old+delta, envir=rho) ans1 <- eval(substitute(expr), rho) assign(theta[i], old, envir=rho) grad[, i] <- (ans1 - ans)/delta } attr(ans, "gradient") <- grad ans } omega <- 1:5; x <- 1; y <- 2 numeric.deriv(sin(omega*x*y), c("x", "y")) |
where expr
is an expression, theta
a character vector of
variable names and rho
the environment to be used.
For the compiled version the call from @R{} will be
.External("numeric_deriv", expr, theta, rho) |
with example usage
.External("numeric_deriv", quote(sin(omega*x*y)), c("x", "y"), .GlobalEnv) |
Note the need to quote the expression to stop it being evaluated.
Here is the complete C code which we will explain section by section.
#include <R.h> /* for DOUBLE_EPS */ #include <Rinternals.h> SEXP numeric_deriv(SEXP args) { SEXP theta, expr, rho, ans, ans1, gradient, par, dimnames; double tt, xx, delta, eps = sqrt(DOUBLE_EPS), *rgr, *rans; int start, i, j; expr = CADR(args); if(!isString(theta = CADDR(args))) error("theta should be of type character"); if(!isEnvironment(rho = CADDDR(args))) error("rho should be an environment"); PROTECT(ans = coerceVector(eval(expr, rho), REALSXP)); PROTECT(gradient = allocMatrix(REALSXP, LENGTH(ans), LENGTH(theta))); rgr = REAL(gradient); rans = REAL(ans); for(i = 0, start = 0; i < LENGTH(theta); i++, start += LENGTH(ans)) { PROTECT(par = findVar(install(CHAR(STRING_ELT(theta, i))), rho)); tt = REAL(par)[0]; xx = fabs(tt); delta = (xx < 1) ? eps : xx*eps; REAL(par)[0] += delta; PROTECT(ans1 = coerceVector(eval(expr, rho), REALSXP)); for(j = 0; j < LENGTH(ans); j++) rgr[j + start] = (REAL(ans1)[j] - rans[j])/delta; REAL(par)[0] = tt; UNPROTECT(2); /* par, ans1 */ } PROTECT(dimnames = allocVector(VECSXP, 2)); SET_VECTOR_ELT(dimnames, 1, theta); dimnamesgets(gradient, dimnames); setAttrib(ans, install("gradient"), gradient); UNPROTECT(3); /* ans gradient dimnames */ return ans; } |
The code to handle the arguments is
expr = CADR(args); if(!isString(theta = CADDR(args))) error("theta should be of type character"); if(!isEnvironment(rho = CADDDR(args))) error("rho should be an environment"); |
Note that we check for correct types of theta
and rho
but
do not check the type of expr
. That is because eval
can
handle many types of @R{} objects other than EXPRSXP
. There is
no useful coercion we can do, so we stop with an error message if the
arguments are not of the correct mode.
The first step in the code is to evaluate the expression in the
environment rho
, by
PROTECT(ans = coerceVector(eval(expr, rho), REALSXP)); |
We then allocate space for the calculated derivative by
PROTECT(gradient = allocMatrix(REALSXP, LENGTH(ans), LENGTH(theta))); |
The first argument to allocMatrix
gives the SEXPTYPE
of
the matrix: here we want it to be REALSXP
. The other two
arguments are the numbers of rows and columns.
for(i = 0, start = 0; i < LENGTH(theta); i++, start += LENGTH(ans)) { PROTECT(par = findVar(install(CHAR(STRING_ELT(theta, i))), rho)); |
Here, we are entering a for loop. We loop through each of the
variables. In the for
loop, we first create a symbol
corresponding to the i
'th element of the STRSXP
theta
. Here, STRING_ELT(theta, i)
accesses the
i
'th element of the STRSXP
theta
. Macro
CHAR()
extracts the actual character
representation(29) of it: it returns a pointer. We then
install the name and use findVar
to find its value.
tt = REAL(par)[0]; xx = fabs(tt); delta = (xx < 1) ? eps : xx*eps; REAL(par)[0] += delta; PROTECT(ans1 = coerceVector(eval(expr, rho), REALSXP)); |
We first extract the real value of the parameter, then calculate
delta
, the increment to be used for approximating the numerical
derivative. Then we change the value stored in par
(in
environment rho
) by delta
and evaluate expr
in
environment rho
again. Because we are directly dealing with
original @R{} memory locations here, @R{} does the evaluation for the
changed parameter value.
for(j = 0; j < LENGTH(ans); j++) rgr[j + start] = (REAL(ans1)[j] - rans[j])/delta; REAL(par)[0] = tt; UNPROTECT(2); } |
Now, we compute the i
'th column of the gradient matrix. Note how
it is accessed: @R{} stores matrices by column (like FORTRAN).
PROTECT(dimnames = allocVector(VECSXP, 2)); SET_VECTOR_ELT(dimnames, 1, theta); dimnamesgets(gradient, dimnames); setAttrib(ans, install("gradient"), gradient); UNPROTECT(3); return ans; } |
First we add column names to the gradient matrix. This is done by
allocating a list (a VECSXP
) whose first element, the row names,
is NULL
(the default) and the second element, the column names,
is set as theta
. This list is then assigned as the attribute
having the symbol R_DimNamesSymbol
. Finally we set the gradient
matrix as the gradient attribute of ans
, unprotect the remaining
protected locations and return the answer ans
.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Suppose an @R{} extension want to accept an @R{} expression from the user and evaluate it. The previous section covered evaluation, but the expression will be entered as text and needs to be parsed first. A small part of @R{}'s parse interface is declared in header file `R_ext/Parse.h'(30).
An example of the usage can be found in the (example) Windows package @pkg{windlgs} included in the @R{} source tree. The essential part is
#include <R.h> #include <Rinternals.h> #include <R_ext/Parse.h> SEXP menu_ttest3() { char cmd[256]; SEXP cmdSexp, cmdexpr, ans = R_NilValue; int i; ParseStatus status; ... if(done == 1) { PROTECT(cmdSexp = allocVector(STRSXP, 1)); SET_STRING_ELT(cmdSexp, 0, mkChar(cmd)); cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue)); if (status != PARSE_OK) { UNPROTECT(2); error("invalid call %s", cmd); } /* Loop is needed here as EXPSEXP will be of length > 1 */ for(i = 0; i < length(cmdexpr); i++) ans = eval(VECTOR_ELT(cmdexpr, i), R_GlobalEnv); UNPROTECT(2); } return ans; } |
Note that a single line of text may give rise to more than one @R{} expression.
R_ParseVector
is essentially the code used to implement
parse(text=)
at @R{} level. The first argument is a character
vector (corresponding to text
) and the second the maximal number
of expressions to parse (corresponding to n
). The third argument
is a pointer to a variable of an enumeration type, and it is normal (as
parse
does) to regard all values other than PARSE_OK
as an
error. Other values which might be returned are PARSE_INCOMPLETE
(an incomplete expression was found) and PARSE_ERROR
(a syntax
error), in both cases the value returned being R_NilValue
.
The fourth argument is a srcfile
object or the @R{} NULL
object (as in the example above). In the former case a srcref
attribute would be attached to the result, containing a list of
srcref
objects of the same length as the expression, to allow it to be
echoed with its original formatting.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The SEXPTYPE
s EXTPTRSXP
and WEAKREFSXP
can be
encountered at @R{} level, but are created in C code.
External pointer SEXP
s are intended to handle references to C
structures such as `handles', and are used for this purpose in package
@pkg{RODBC} for example. They are unusual in their copying semantics in
that when an @R{} object is copied, the external pointer object is not
duplicated. (For this reason external pointers should only be used as
part of an object with normal semantics, for example an attribute or an
element of a list.)
An external pointer is created by
SEXP R_MakeExternalPtr(void *p, SEXP tag, SEXP prot); |
where p
is the pointer (and hence this cannot portably be a
function pointer), and tag
and prot
are references to
ordinary R objects which will remain in existence (be protected from
garbage collection) for the lifetime of the external pointer object.
A useful convention is to use the tag
field for some form of
type identification and the prot
field for protecting the
memory that the external pointer represents, if that memory is
allocated from the R heap. Both tag
and prot
can be
R_NilValue
, and often are.
The elements of an external pointer can be accessed and set via
void *R_ExternalPtrAddr(SEXP s); SEXP R_ExternalPtrTag(SEXP s); SEXP R_ExternalPtrProtected(SEXP s); void R_ClearExternalPtr(SEXP s); void R_SetExternalPtrAddr(SEXP s, void *p); void R_SetExternalPtrTag(SEXP s, SEXP tag); void R_SetExternalPtrProtected(SEXP s, SEXP p); |
Clearing a pointer sets its value to the C NULL
pointer.
 This can be @R{} code or C code, and the various interfaces are
void R_RegisterFinalizer(SEXP s, SEXP fun); void R_RegisterFinalizerEx(SEXP s, SEXP fun, Rboolean onexit); typedef void (*R_CFinalizer_t)(SEXP); void R_RegisterCFinalizer(SEXP s, R_CFinalizer_t fun); void R_RegisterCFinalizerEx(SEXP s, R_CFinalizer_t fun, Rboolean onexit); |
The @R{} function indicated by fun
should be a function of a
single argument, the object to be finalized. @R{} does not perform a
garbage collection when shutting down, and the onexit
argument of
the extended forms can be used to ask that the finalizer be run during a
normal shutdown of the @R{} session. It is suggested that it is good
practice to clear the pointer on finalization.
The only @R{} level function for interacting with external pointers is
reg.finalizer
which can be used to set a finalizer.
It is probably not a good idea to allow an external pointer to be
save
d and then reloaded, but if this happens the pointer will be
set to the C NULL
pointer.
Weak references are used to allow the programmer to maintain information on entities without preventing the garbage collection of the entities once they become unreachable.
A weak reference contains a key and a value. The value is reachable is
if it either reachable directly or via weak references with reachable
keys. Once a value is determined to be unreachable during garbage
collection, the key and value are set to R_NilValue
and the
finalizer will be run later in the garbage collection.
Weak reference objects are created by one of
SEXP R_MakeWeakRef(SEXP key, SEXP val, SEXP fin, Rboolean onexit); SEXP R_MakeWeakRefC(SEXP key, SEXP val, R_CFinalizer_t fin, Rboolean onexit); |
where the @R{} or C finalizer are specified in exactly the same way as for an external pointer object (whose finalization interface is implemented via weak references).
The parts can be accessed via
SEXP R_WeakRefKey(SEXP w); SEXP R_WeakRefValue(SEXP w); void R_RunWeakRefFinalizer(SEXP w); |
A toy example of the use of weak references can be found at
www.stat.uiowa.edu/~luke/R/references/weakfinex.html
,
but that is used to add finalizers to external pointers which can now be
done more directly.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The vector accessors like REAL
and INTEGER
and
VECTOR_ELT
are functions when used in @R{} extensions.
(For efficiency they are macros when used in the @R{} source code, apart
from SET_STRING_ELT
and SET_VECTOR_ELT
which are always
functions.)
The accessor functions check that they are being used on an appropriate
type of SEXP
. By default a certain amount of misuse is allowed
where the internal representation is the same: for example
LOGICAL
can be used on a INTSXP
and SET_VECTOR_ELT
on a STRSXP
. Strict checking can be enabled by compiling @R{}
(specifically `src/main/memory.c') with
`USE_TYPE_CHECKING_STRICT' defined (e.g. in as the configure
variable `DEFS' on a Unix-alike).
If efficiency is essential, the macro versions of the accessors can be obtained by defining `USE_RINTERNALS' before including `Rinternals.h'. If you find it necessary to do so, please do test that your code compiled without `USE_RINTERNALS' defined, as this provides a stricter test that the accessors have been used correctly.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
As from @R{} 2.5.0 CHARSXP
s can be marked as coming from a known
encoding (Latin-1 or UTF-8). This is mainly intended for human-readable
output, and most packages can just treat such CHARSXP
s as a
whole. However, if they need to be interpreted as characters or output
at C level then it would normally be correct to ensure that they are
converted to the encoding of the current locale: this can be done by
accessing the data in the CHARSXP
by translateChar
rather
than by CHAR
. If re-encoding is needed this allocates memory
with R_alloc
which thus persists to the end of the
.Call
/.External
call unless vmaxset
is used.
As from @R{} 2.7.0 there is a similar function translateCharUTF8
which converts to UTF-8: this has the advantage that a faithful
translation is almost always possible (whereas only a few languages can
be represented in the encoding of the current locale unless that is
UTF-8).
@R{} can be built without iconv
(although this is very much
discouraged) in which case these functions exist but do no translation:
such a build of @R{} is in any case not suitable for handling
non-ASCII data.
As from @R{} 2.7.0 there is a public interface to the encoding marked on
CHARXSXPs
via
typedef enum {CE_NATIVE, CE_UTF8, CE_LATIN1, CE_SYMBOL, CE_ANY} cetype_t; cetype_t getCharCE(SEXP); SEXP mkCharCE(const char *, cetype_t); |
Only the CE_UTF8
and CE_LATIN1
are marked on
CHARSXPs
(and so Rf_getCharCE
will only return one of the
first three), and these should only be used on non-ASCII
strings. Value CE_SYMBOL
is used internally to indicate Adobe
Symbol encoding. Value CE_ANY
is used to indicate a character
string that will not need re-encoding - this is used for character
strings known to be in ASCII, and can also be used as an input
parameter where the intention is that the string is treated as a series
of bytes.
Function
const char *reEnc(const char *x, cetype_t ce_in, cetype_t ce_out, int subst); |
can be used to re-encode character strings: like translateChar
it
returns a string allocated by R_alloc
. This can translate from
CE_SYMBOL
to CE_UTF8
, but not conversely. Argument
subst
controls what to do with untranslatable characters or
invalid input: this is done byte-by-byte with 1
indicates to
output hex of the form <a0>
, and 2
to replace by .
,
with any other value causing the byte to produce no output.
@R{} 2.8.0 added
SEXP mkCharLenCE(const char *, int, cetype_t); |
to create marked character strings of a given length.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There are a large number of entry points in the @R{} executable/DLL that can be called from C code (and some that can be called from FORTRAN code). Only those documented here are stable enough that they will only be changed with considerable notice.
The recommended procedure to use these is to include the header file `R.h' in your C code by
#include <R.h> |
This will include several other header files from the directory `R_INCLUDE_DIR/R_ext', and there are other header files there that can be included too, but many of the features they contain should be regarded as undocumented and unstable.
An alternative is to include the header file `S.h', which may be
useful when porting code from @Sl{}. This includes rather less than
`R.h', and has extra some compatibility definitions (for example
the S_complex
type from @Sl{}).
The defines used for compatibility with @Sl{} sometimes causes
conflicts (notably with Windows headers), and the known
problematic defines can be removed by defining STRICT_R_HEADERS
.
Most of these header files, including all those included by `R.h',
can be used from C++ code. Some others need to be included within an
extern "C"
declaration, and for clarity this is advisable for all
@R{} header files.
Note: Because @R{} re-maps many of its external names to avoid clashes with user code, it is essential to include the appropriate header files when using these entry points.
This remapping can cause problems(31), and can
be eliminated by defining R_NO_REMAP
and prepending `Rf_' to
all the function names used from `Rinternals.h' and
`R_ext/Error.h'.
We can classify the entry points as
Entry points which are documented in this manual and declared in an installed header file. These can be used in distributed packages and will only be changed after deprecation.
Entry points declared in an installed header file that are exported on all @R{} platforms but are not documented and subject to change without notice.
Entry points that are used when building @R{} and exported on all @R{} platforms but are not declared in the installed header files. Do not use these in distributed code.
Entry points that are where possible (Windows and some modern Unix compilers/loaders when using @R{} as a shared library) not exported.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
| 6.1.1 Transient storage allocation | ||
| 6.1.2 User-controlled memory |
There are two types of memory allocation available to the C programmer, one in which @R{} manages the clean-up and the other in which user has full control (and responsibility).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Here @R{} will reclaim the memory at the end of the call to .C
.
Use
char *R_alloc(size_t n, int size) |
which allocates n units of size bytes each. A typical usage (from package @pkg{stats}) is
x = (int *) R_alloc(nrows(merge)+2, sizeof(int)); |
(size_t
is defined in `stddef.h' which the header defining
R_alloc
includes.)
There is a similar call, S_alloc
(for compatibility with older
versions of @Sl{}) which zeroes the memory allocated,
char *S_alloc(long n, int size) |
and
char *S_realloc(char *p, long new, long old, int size) |
which changes the allocation size from old to new units, and zeroes the additional units.
For compatibility with current versions of @Sl{}, header `S.h' (only) defines wrapper macros equivalent to
type* Salloc(long n, int type) type* Srealloc(char *p, long new, long old, int type) |
This memory is taken from the heap, and released at the end of the
.C
, .Call
or .External
call. Users can also manage
it, by noting the current position with a call to vmaxget
and
clearing memory allocated subsequently by a call to vmaxset
.
This is only recommended for experts.
Note that this memory will be freed on error or user interrupt (if allowed: see section Allowing interrupts).
Note that although n is long
, there are limits imposed by
@R{}'s internal allocation mechanism. These will only come into play on
64-bit systems, where the current limit for n is just under 16Gb.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The other form of memory allocation is an interface to malloc
,
the interface providing @R{} error handling. This memory lasts until
freed by the user and is additional to the memory allocated for the @R{}
workspace.
The interface functions are
type* Calloc(size_t n, type) type* Realloc(any *p, size_t n, type) void Free(any *p) |
providing analogues of calloc
, realloc
and free
.
If there is an error during allocation it is handled by @R{}, so if
these routines return the memory has been successfully allocated or
freed. Free
will set the pointer p to NULL
. (Some
but not all versions of @Sl{} do so.)
Users should arrange to Free
this memory when no longer needed,
including on error or user interrupt. This can often be done most
conveniently from an on.exit
action in the calling @R{} function
- see pwilcox
for an example.
Do not assume that memory allocated by Calloc
/Realloc
comes from the same pool as used by malloc
: in particular do not
use free
or strdup
with it.
These entry points need to be prefixed by R_
if
STRICT_R_HEADERS
has been defined.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The basic error handling routines are the equivalents of stop
and
warning
in @R{} code, and use the same interface.
void error(const char * format, ...); void warning(const char * format, ...); |
These have the same call sequences as calls to printf
, but in the
simplest case can be called with a single character string argument
giving the error message. (Don't do this if the string contains `%'
or might otherwise be interpreted as a format.)
If STRICT_R_HEADERS
is not defined there is also an
@Sl{}-compatibility interface which uses calls of the form
PROBLEM ...... ERROR MESSAGE ...... WARN PROBLEM ...... RECOVER(NULL_ENTRY) MESSAGE ...... WARNING(NULL_ENTRY) |
the last two being the forms available in all @Sl{} versions. Here
`......' is a set of arguments to printf
, so can be a string
or a format string followed by arguments separated by commas.
| 6.2.1 Error handling from FORTRAN |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There are two interface function provided to call error
and
warning
from FORTRAN code, in each case with a simple character
string argument. They are defined as
subroutine rexit(message) subroutine rwarn(message) |
Messages of more than 255 characters are truncated, with a warning.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The interface to @R{}'s internal random number generation routines is
double unif_rand(); double norm_rand(); double exp_rand(); |
giving one uniform, normal or exponential pseudo-random variate. However, before these are used, the user must call
GetRNGstate(); |
and after all the required variates have been generated, call
PutRNGstate(); |
These essentially read in (or create) .Random.seed
and write it
out after use.
File `S.h' defines seed_in
and seed_out
for
@Sl{}-compatibility rather than GetRNGstate
and
PutRNGstate
. These take a long *
argument which is
ignored.
The random number generator is private to @R{}; there is no way to select the kind of RNG or set the seed except by evaluating calls to the @R{} functions.
The C code behind @R{}'s rxxx
functions can be accessed by
including the header file `Rmath.h'; See section Distribution functions. Those calls generate a single variate and should also be
enclosed in calls to GetRNGstate
and PutRNGstate
.
In addition, there is an interface (defined in header `R_ext/Applic.h') to the generation of random 2-dimensional tables with given row and column totals using Patefield's algorithm.
Here, nrow and ncol give the numbers nr and nc of rows and columns and nrowt and ncolt the corresponding row and column totals, respectively, ntotal gives the sum of the row (or columns) totals, jwork is a workspace of length nc, and on output matrix a contains the nr * nc generated random counts in the usual column-major order.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
A set of functions is provided to test for NA
, Inf
,
-Inf
and NaN
. These functions are accessed via macros:
ISNA(x) True for R's |
and via function R_IsNaN
which is true for NaN
but not
NA
.
Do use R_FINITE
rather than isfinite
or finite
; the
latter is often mendacious and isfinite
is only available on a
few platforms, on which R_FINITE
is a macro expanding to
isfinite
.
Currently in C code ISNAN
is a macro calling isnan
.
(Since this gives problems on some C++ systems, if the @R{} headers is
called from C++ code a function call is used.)
You can check for Inf
or -Inf
by testing equality to
R_PosInf
or R_NegInf
, and set (but not test) an NA
as NA_REAL
.
All of the above apply to double variables only. For integer
variables there is a variable accessed by the macro NA_INTEGER
which can used to set or test for missingness.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The most useful function for printing from a C routine compiled into
@R{} is Rprintf
. This is used in exactly the same way as
printf
, but is guaranteed to write to @R{}'s output (which might
be a GUI console rather than a file). It is wise to write
complete lines (including the "\n"
) before returning to @R{}.
The function REprintf
is similar but writes on the error stream
(stderr
) which may or may not be different from the standard
output stream. Functions Rvprintf
and REvprintf
are
analogues using the vprintf
interface.
| 6.5.1 Printing from FORTRAN |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
On many systems FORTRAN write
and print
statements can be
used, but the output may not interleave well with that of C, and will be
invisible on GUI interfaces. They are not portable and best
avoided.
Three subroutines are provided to ease the output of information from FORTRAN code.
subroutine dblepr(label, nchar, data, ndata) subroutine realpr(label, nchar, data, ndata) subroutine intpr (label, nchar, data, ndata) |
Here label is a character label of up to 255 characters,
nchar is its length (which can be -1
if the whole label is
to be used), and data is an array of length at least ndata
of the appropriate type (double precision
, real
and
integer
respectively). These routines print the label on one
line and then print data as if it were an @R{} vector on
subsequent line(s). They work with zero ndata, and so can be used
to print a label alone.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Naming conventions for symbols generated by FORTRAN differ by platform: it is not safe to assume that FORTRAN names appear to C with a trailing underscore. To help cover up the platform-specific differences there is a set of macros that should be used.
F77_SUB(name)
to define a function in C to be called from FORTRAN
F77_NAME(name)
to declare a FORTRAN routine in C before use
F77_CALL(name)
to call a FORTRAN routine from C
F77_COMDECL(name)
to declare a FORTRAN common block in C
F77_COM(name)
to access a FORTRAN common block from C
On most current platforms these are all the same, but it is unwise to rely on this. Note that names with underscores are not legal in FORTRAN 77, and are not portably handled by the above macros. (Also, all FORTRAN names for use by @R{} are lower case, but this is not enforced by the macros.)
For example, suppose we want to call R's normal random numbers from FORTRAN. We need a C wrapper along the lines of
#include <R.h> void F77_SUB(rndstart)(void) { GetRNGstate(); } void F77_SUB(rndend)(void) { PutRNGstate(); } double F77_SUB(normrnd)(void) { return norm_rand(); } |
to be called from FORTRAN as in
subroutine testit() double precision normrnd, x call rndstart() x = normrnd() call dblepr("X was", 5, x, 1) call rndend() end |
Note that this is not guaranteed to be portable, for the return conventions might not be compatible between the C and FORTRAN compilers used. (Passing values via arguments is safer.)
The standard packages, for example @pkg{stats}, are a rich source of further examples.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
@R{} contains a large number of mathematical functions for its own use, for example numerical linear algebra computations and special functions.
The header files `R_ext/BLAS.h', `R_ext/Lapack.h' and `R_ext/Linpack.h' contains declarations of the BLAS, LAPACK and LINPACK/EISPACK linear algebra functions included in @R{}. These are expressed as calls to FORTRAN subroutines, and they will also be usable from users' FORTRAN code. Although not part of the official API, this set of subroutines is unlikely to change (but might be supplemented).
The header file `Rmath.h' lists many other functions that are available and documented in the following subsections. Many of these are C interfaces to the code behind @R{} functions, so the @R{} function documentation may give further details.
| 6.7.1 Distribution functions | ||
| 6.7.2 Mathematical functions | ||
| 6.7.3 Numerical Utilities | ||
| 6.7.4 Mathematical constants |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The routines used to calculate densities, cumulative distribution functions and quantile functions for the standard statistical distributions are available as entry points.
The arguments for the entry points follow the pattern of those for the normal distribution:
double dnorm(double x, double mu, double sigma, int give_log); double pnorm(double x, double mu, double sigma, int lower_tail, int give_log); double qnorm(double p, double mu, double sigma, int lower_tail, int log_p); double rnorm(double mu, double sigma); |
That is, the first argument gives the position for the density and CDF
and probability for the quantile function, followed by the
distribution's parameters. Argument lower_tail should be
TRUE
(or 1
) for normal use, but can be FALSE
(or
0
) if the probability of the upper tail is desired or specified.
Finally, give_log should be non-zero if the result is required on log scale, and log_p should be non-zero if p has been specified on log scale.
Note that you directly get the cumulative (or "integrated") hazard function, @eqn{H(t) = - \log(1 - F(t)), H(t) = - log(1 - F(t))}, by using
- pdist(t, ..., /*lower_tail = */ FALSE, /* give_log = */ TRUE) |
or shorter (and more cryptic) - pdist(t, ..., 0, 1)
.
The random-variate generation routine rnorm
returns one normal
variate. See section Random number generation, for the protocol in using the
random-variate routines.
Note that these argument sequences are (apart from the names and that
rnorm
has no n) mainly the same as the corresponding @R{}
functions of the same name, so the documentation of the @R{} functions
can be used. Note that the exponential and gamma distributions are
parametrized by scale
rather than rate
.
For reference, the following table gives the basic name (to be prefixed by `d', `p', `q' or `r' apart from the exceptions noted) and distribution-specific arguments for the complete set of distributions.
beta
beta
a
,b
non-central beta
nbeta
a
,b
,ncp
binomial
binom
n
,p
Cauchy
cauchy
location
,scale
chi-squared
chisq
df
non-central chi-squared
nchisq
df
,ncp
exponential
exp
scale
(and notrate
)F
f
n1
,n2
non-central F
nf
n1
,n2
,ncp
gamma
gamma
shape
,scale
geometric
geom
p
hypergeometric
hyper
NR
,NB
,n
logistic
logis
location
,scale
lognormal
lnorm
logmean
,logsd
negative binomial
nbinom
size
,prob
normal
norm
mu
,sigma
Poisson
pois
lambda
Student's t
t
n
non-central t
nt
df
,delta
Studentized range
tukey
(*)
rr
,cc
,df
uniform
unif
a
,b
Weibull
weibull
shape
,scale
Wilcoxon rank sum
wilcox
m
,n
Wilcoxon signed rank
signrank
n
Entries marked with an asterisk only have `p' and `q'
functions available, and none of the non-central distributions have
`r' functions. After a call to dwilcox
, pwilcox
or
qwilcox
the function wilcox_free()
should be called, and
similarly for the signed rank functions.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The Gamma function, the natural logarithm of its absolute value and first four derivatives and the n-th derivative of Psi, the digamma function.
The (complete) Beta function and its natural logarithm.
The number of combinations of k items chosen from from n and its natural logarithm. k is rounded to the nearest integer (with a warning if needed).
Bessel functions of types I, J, K and Y with index nu. For
bessel_i
and bessel_k
there is the option to return
exp(-x) I(x; nu) or exp(x) K(x;
nu) if expo is 2. (Use expo == 1
for unscaled
values.)
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
There are a few other numerical utility functions available as entry points.
R_pow(x, y)
and R_pow_di(x, i)
compute x^y
and x^i
, respectively
using R_FINITE
checks and returning the proper result (the same
as @R{}) for the cases where x, y or i are 0 or
missing or infinite or NaN
.
pythag(a, b)
computes sqrt(a^2 +
b^2)
without overflow or destructive underflow: for example it
still works when both a and b are between 1e200
and
1e300
(in IEEE double precision).
Computes log(1 + x)
(log 1 plus x), accurately
even for small x, i.e., @eqn{|x| \ll 1, |x| << 1}.
This may be provided by your platform, in which case it is not included
in `Rmath.h', but is (probably) in `math.h' which
`Rmath.h' includes. For backwards compatibility with @R{} versions
prior to 1.5.0, the entry point Rf_log1p
is still provided.
Computes log(1 + x) - x
(log 1 plus x minus x),
accurately even for small x, i.e., @eqn{|x| \ll 1, |x| << 1}.
Computes exp(x) - 1
(exp x minus 1), accurately
even for small x, i.e., @eqn{|x| \ll 1, |x| << 1}.
This may be provided by your platform, in which case it is not included in `Rmath.h', but is (probably) in `math.h' which `Rmath.h' includes.
Computes log(gamma(x + 1))
(log(gamma(1 plus x))),
accurately even for small x, i.e., @eqn{0 < x < 0.5, 0 < x < 0.5}.
Compute the log of a sum or difference from logs of terms, i.e.,
"x + y" as log (exp(logx) + exp(logy))
and
"x - y" as log (exp(logx) - exp(logy))
,
without causing overflows or throwing away too much accuracy.
Return the larger (max
) or smaller (min
) of two integer or
double numbers, respectively.
Compute the signum function, where sign(x) is 1, 0, or -1, when x is positive, 0, or negative, respectively.
Performs "transfer of sign" and is defined as @eqn{|x| * \hbox{sign}(y), |x| * sign(y).
Returns the value of x rounded to digits decimal digits (after the decimal point).
This is the function used by @R{}'s round()
.
Returns the value of x rounded to digits significant decimal digits.
This is the function used by @R{}'s signif()
.
Returns the value of x truncated (to an integer value) towards zero.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
@R{} has a set of commonly used mathematical constants encompassing
constants usually found `math.h' and contains further ones that are
used in statistical computations. All these are defined to (at least)
30 digits accuracy in `Rmath.h'. The following definitions
use ln(x)
for the natural logarithm (log(x)
in @R{}).
Name
Definition (
ln = log
)round(value, 7)
M_E
e
2.7182818
M_LOG2E
log2(e)
1.4426950
M_LOG10E
log10(e)
0.4342945
M_LN2
ln(2)
0.6931472
M_LN10
ln(10)
2.3025851
M_PI
@eqn{\pi, pi}
3.1415927
M_PI_2
@eqn{\pi/2, pi/2}
1.5707963
M_PI_4
@eqn{\pi/4, pi/4}
0.7853982
M_1_PI
@eqn{1/\pi, 1/pi}
0.3183099
M_2_PI
@eqn{2/\pi, 2/pi}
0.6366198
M_2_SQRTPI
2/sqrt(@eqn{\pi, pi})
1.1283792
M_SQRT2
sqrt(2)
1.4142136
M_SQRT1_2
1/sqrt(2)
0.7071068
M_SQRT_3
sqrt(3)
1.7320508
M_SQRT_32
sqrt(32)
5.6568542
M_LOG10_2
log10(2)
0.3010300
M_2PI
@eqn{2\pi, 2*pi}
6.2831853
M_SQRT_PI
sqrt(@eqn{\pi, pi})
1.7724539
M_1_SQRT_2PI
1/sqrt(@eqn{2\pi, 2*pi})
0.3989423
M_SQRT_2dPI
sqrt(2/@eqn{\pi, pi})
0.7978846
M_LN_SQRT_PI
ln(sqrt(@eqn{\pi, pi}))
0.5723649
M_LN_SQRT_2PI
ln(sqrt(@eqn{2\pi, 2*pi}))
0.9189385
M_LN_SQRT_PId2
ln(sqrt(@eqn{\pi, pi}/2))
0.2257914
There are a set of constants (PI
, DOUBLE_EPS
) (and so on)
defined (unless STRICT_R_HEADERS
is defined) in the included
header `R_ext/Constants.h', mainly for compatibility with @Sl{}.
Further, the included header `R_ext/Boolean.h' has constants
TRUE
and FALSE = 0
of type Rboolean
in order to
provide a way of using "logical" variables in C consistently.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The C code underlying optim
can be accessed directly. The user
needs to supply a function to compute the function to be minimized, of
the type
typedef double optimfn(int n, double *par, void *ex); |
where the first argument is the number of parameters in the second argument. The third argument is a pointer passed down from the calling routine, normally used to carry auxiliary information.
Some of the methods also require a gradient function
typedef void optimgr(int n, double *par, double *gr, void *ex); |
which passes back the gradient in the gr
argument. No function
is provided for finite-differencing, nor for approximating the Hessian
at the result.
The interfaces (defined in header `R_ext/Applic.h') are
void nmmin(int n, double *xin, double *x, double *Fmin, optimfn fn, int *fail, double abstol, double intol, void *ex, double alpha, double beta, double gamma, int trace, int *fncount, int maxit); |
void vmmin(int n, double *x, double *Fmin, optimfn fn, optimgr gr, int maxit, int trace, int *mask, double abstol, double reltol, int nREPORT, void *ex, int *fncount, int *grcount, int *fail); |
void cgmin(int n, double *xin, double *x, double *Fmin, optimfn fn, optimgr gr, int *fail, double abstol, double intol, void *ex, int type, int trace, int *fncount, int *grcount, int maxit); |
void lbfgsb(int n, int lmm, double *x, double *lower, double *upper, int *nbd, double *Fmin, optimfn fn, optimgr gr, int *fail, void *ex, double factr, double pgtol, int *fncount, int *grcount, int maxit, char *msg, int trace, int nREPORT); |
void samin(int n, double *x, double *Fmin, optimfn fn, int maxit, int tmax, double temp, int trace, void *ex); |
Many of the arguments are common to the various methods. n
is
the number of parameters, x
or xin
is the starting
parameters on entry and x
the final parameters on exit, with
final value returned in Fmin
. Most of the other parameters can
be found from the help page for optim
: see the source code
`src/appl/lbfgsb.c' for the values of nbd
, which
specifies which bounds are to be used.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The C code underlying integrate
can be accessed directly. The
user needs to supply a vectorizing C function to compute the
function to be integrated, of the type
typedef void integr_fn(double *x, int n, void *ex); |
where x[]
is both input and output and has length n
, i.e.,
a C function, say fn
, of type integr_fn
must basically do
for(i in 1:n) x[i] := f(x[i], ex)
. The vectorization requirement
can be used to speed up the integrand instead of calling it n
times. Note that in the current implementation built on QUADPACK,
n
will be either 15 or 21. The ex
argument is a pointer
passed down from the calling routine, normally used to carry auxiliary
information.
There are interfaces (defined in header `R_ext/Applic.h') for definite and for indefinite integrals. `Indefinite' means that at least one of the integration boundaries is not finite.
void Rdqags(integr_fn f, void *ex, double *a, double *b, double *epsabs, double *epsrel, double *result, double *abserr, int *neval, int *ier, int *limit, int *lenw, int *last, int *iwork, double *work); |
void Rdqagi(integr_fn f, void *ex, double *bound, int *inf, double *epsabs, double *epsrel, double *result, double *abserr, int *neval, int *ier, int *limit, int *lenw, int *last, int *iwork, double *work); |
Only the 3rd and 4th argument differ for the two integrators; for the
definite integral, using Rdqags
, a
and b
are the
integration interval bounds, whereas for an indefinite integral, using
Rdqagi
, bound
is the finite bound of the integration (if
the integral is not doubly-infinite) and inf
is a code indicating
the kind of integration range,
inf = 1
corresponds to (bound, +Inf),
inf = -1
corresponds to (-Inf, bound),
inf = 2
corresponds to (-Inf, +Inf),
f
and ex
define the integrand function, see above;
epsabs
and epsrel
specify the absolute and relative
accuracy requested, result
, abserr
and last
are the
output components value
, abs.err
and subdivisions
of the @R{} function integrate, where neval
gives the number of
integrand function evaluations, and the error code ier
is
translated to @R{}'s integrate() $ message
, look at that function
definition. limit
corresponds to integrate(...,
subdivisions = *)
. It seems you should always define the two work
arrays and the length of the second one as
lenw = 4 * limit; iwork = (int *) R_alloc(limit, sizeof(int)); work = (double *) R_alloc(lenw, sizeof(double)); |
The comments in the source code in `src/appl/integrate.c' give
more details, particularly about reasons for failure (ier >= 1
).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
@R{} has a fairly comprehensive set of sort routines which are made available to users' C code. These are declared in header file `R_ext/Utils.h' (included by `R.h') and include the following.
The first three sort integer, real (double) and complex data
respectively. (Complex numbers are sorted by the real part first then
the imaginary part.) NA
s are sorted last.
rsort_with_index
sorts on x, and applies the same
permutation to index. NA
s are sorted last.
Is similar to rsort_with_index
but sorts into decreasing order,
and NA
s are not handled.
These all provide (very) partial sorting: they permute x so that
x[k]
is in the correct place with smaller values to
the left, larger ones to the right.
These routines sort v[i:j]
or
iv[i:j]
(using 1-indexing, i.e.,
v[1]
is the first element) calling the quicksort algorithm
as used by @R{}'s sort(v, method = "quick")
and documented on the
help page for the @R{} function sort
. The ..._I()
versions also return the sort.index()
vector in I
. Note
that the ordering is not stable, so tied values may be permuted.
Note that NA
s are not handled (explicitly) and you should
use different sorting functions if NA
s can be present.
The FORTRAN interface routines for sorting double precision vectors are
qsort3
and qsort4
, equivalent to R_qsort
and
R_qsort_I
, respectively.
Given the nr by nc matrix matrix
in column-major
("FORTRAN")
order, R_max_col()
returns in maxes[i-1]
the
column number of the maximal element in the i-th row (the same as
@R{}'s max.col()
function). In the case of ties (multiple maxima),
*ties_meth
is an integer code in 1:3
determining the method:
1 = "random", 2 = "first" and 3 = "last".
See @R{}'s help page ?max.col
.
Given the ordered vector xt of length n, return the interval
or index of x in xt[]
, typically max(i; @eqn{1
\le i \le n, 1 <= i <= n} & xt[i] @eqn{\le, <=}
x) where we use 1-indexing as in @R{} and FORTRAN (but not C). If
rightmost_closed is true, also returns n-1 if x
equals xt[n]. If all_inside is not 0, the
result is coerced to lie in 1:(n-1)
even when x is
outside the xt[] range. On return, *mflag
equals
-1 if x < xt[1], +1 if x >=
xt[n], and 0 otherwise.
The algorithm is particularly fast when ilo is set to the last
result of findInterval()
and x is a value of a sequence which
is increasing or decreasing for subsequent calls.
There is also an F77_CALL(interv)()
version of
findInterval()
with the same arguments, but all pointers.
The following two functions do numerical colorspace conversion from HSV to RGB and back. Note that all colours must be in [0,1].
A system-independent interface to produce the name of a temporary file is provided as
Return a pathname for a temporary file with name beginning with
prefix. A NULL
prefix is replaced by ""
.
There is also the internal function used to expand file names in several
@R{} functions, and called directly by path.expand
.
Expand a path name fn by replacing a leading tilde by the user's
home directory (if defined). The precise meaning is platform-specific;
it will usually be taken from the environment variable HOME
if
this is defined.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
@R{} has its own C-level interface to the encoding conversion
capabilities provided by iconv
, for the following reasons
iconv
was available at configure time.
iconv
.
These are declared in header file `R_ext/Riconv.h'.
Set up a pointer to an encoding object to be used to convert between two
encodings: ""
indicates the current locale.
Convert as much as possible of inbuf
to outbuf
. Initially
the int
variables indicate the number of bytes available in the
buffers, and they are updated (and the char
pointers are updated
to point to the next free byte in the buffer). The return value is the
number of characters converted, or (size_t)-1
(beware:
size_t
is usually an unsigned type). It should be safe to assume
that an error condition sets errno
to one of E2BIG
(the
output buffer is full), EILSEQ
(the input cannot be converted,
and might be invalid in the encoding specified) or EINVAL
(the
input does not end with a complete multi-byte character).
Free the resources of an encoding object.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
No port of @R{} can be interrupted whilst running long computations in compiled code, so programmers should make provision for the code to be interrupted at suitable points by calling from C
#include <R_ext/Utils.h> void R_CheckUserInterrupt(void); |
and from FORTRAN
subroutine rchkusr() |
These check if the user has requested an interrupt, and if so branch to @R{}'s error handling functions.
Note that it is possible that the code behind one of the entry points defined here if called from your C or FORTRAN code could be interruptible or generate an error and so not return to your code.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The header files define USING_R
, which can be used to test if
the code is indeed being used with @R{}.
Header file `Rconfig.h' (included by `R.h') is used to define
platform-specific macros that are mainly for use in other header files.
The macro WORDS_BIGENDIAN
is defined on big-endian systems
(e.g. sparc-sun-solaris2.6
) and not on little-endian systems
(such as i686
under Linux or Windows). It can be useful when
manipulating binary files.
Header file `Rversion.h' (not included by `R.h')
defines a macro R_VERSION
giving the version number encoded as an
integer, plus a macro R_Version
to do the encoding. This can be
used to test if the version of @R{} is late enough, or to include
back-compatibility features. For protection against very old versions
of @R{} which did not have this macro, use a construction such as
#if defined(R_VERSION) && R_VERSION >= R_Version(1, 9, 0) ... #endif |
More detailed information is available in the macros R_MAJOR
,
R_MINOR
, R_YEAR
, R_MONTH
and R_DAY
: see the
header file `Rversion.h' for their format. Note that the minor
version includes the patchlevel (as in `9.0').
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The C99 keyword inline
is recognized by some compilers used to
build @R{} whereas others need __inline__
or do not support
inlining. Portable code can be written using the macro R_INLINE
(defined in file `Rconfig.h' included by `R.h'), as for
example from package @pkg{cluster}
#include <R.h> static R_INLINE int ind_2(int l, int j) { ... } |
Be aware that using inlining with functions in more than one compilation
unit is almost impossible to do portably: see
http://www.greenend.org.uk/rjk/2003/03/inline.html. All the @R{}
configure code has checked is that R_INLINE
can be used in a
single C file with the compiler used to build @R{}. We recommend that
packages making extensive use of inlining include their own configure code.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
Header `R_ext/Visibility' has some definitions for controlling the
visibility of entry points. These are only effective when
`HAVE_VISIBILITY_ATTRIBUTE' is defined - this is checked when @R{}
is configured and recorded in header `Rconfig.h' (included by
`R_ext/Visibility.h'). It is generally defined on modern
Unix-alikes with a recent compiler (e.g. gcc4
), but not
supported on Windows. Minimizing the visibility of symbols in a shared
library will both speed up its loading (unlikely to be significant) and
reduce the possibility of linking to the wrong entry points of the same
name.
C/C++ entry points prefixed by attribute_hidden
will not be
visible in the shared object. There is no comparable mechanism for
FORTRAN entry points, but there is a more comprehensive scheme used by,
for example package @pkg{stats}. Most compilers which allow control of
visibility will allow control of visibility for all symbols via a flag,
and where known the flag is encapsulated in the macros
`C_VISIBILITY' and F77_VISIBILITY
for C and FORTRAN
compilers. These are defined in `etc/Makeconf' and so available
for normal compilation of package code. For example,
`src/Makevars' could include
PKG_CFLAGS=$(C_VISIBILITY) PKG_FFLAGS=$(F77_VISIBILITY) |
This would end up with no visible entry points, which would be
pointless. However, the effect of the flags can be overridden by using
the attribute_visible
prefix. A shared object which registers
its entry points needs only for have one visible entry point, its
initializer, so for example package @pkg{stats} has
void attribute_visible R_init_stats(DllInfo *dll) { R_registerRoutines(dll, CEntries, CallEntries, FortEntries, NULL); R_useDynamicSymbols(dll, FALSE); ... } |
The visibility mechanism is not available on Windows, but there is an equally effective way to control which entry points are visible, by supplying a definitions file `pkgnme/src/pkgname-win.def': only entry points listed in that file will be visible. Again using @pkg{stats} as an example, it has
LIBRARY stats.dll EXPORTS R_init_stats |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
It is possible to build Mathlib
, the @R{} set of mathematical
functions documented in `Rmath.h', as a standalone library
`libRmath' under both Unix and Windows. (This includes the
functions documented in Numerical analysis subroutines as from
that header file.)
The library is not built automatically when @R{} is installed, but can be built in the directory `src/nmath/standalone' in the @R{} sources: see the file `README' there. To use the code in your own C program include
#define MATHLIB_STANDALONE #include <Rmath.h> |
and link against `-lRmath' (and perhaps `-lm'. There is an example file `test.c'.
A little care is needed to use the random-number routines. You will need to supply the uniform random number generator
double unif_rand(void) |
or use the one supplied (and with a dynamic library or DLL you will have to use the one supplied, which is the Marsaglia-multicarry with an entry points
set_seed(unsigned int, unsigned int) |
to set its seeds and
get_seed(unsigned int *, unsigned int *) |
to read the seeds).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
The header files which @R{} installs are in directory `R_INCLUDE_DIR' (default `R_HOME/include'). This currently includes
`R.h'
includes many other files
`S.h'
different version for code ported from @Sl{}
`Rinternals.h'
definitions for using @R{}'s internal structures
`Rdefines.h'
macros for an @Sl{}-like interface to the above
`Rmath.h'
standalone math library
`Rversion.h'
@R{} version information
`Rinterface.h'
for add-on front-ends (Unix-alikes only)
`Rembedded.h'
for add-on front-ends
`R_ext/Applic.h'
optimization and integration
`R_ext/BLAS.h'
C definitions for BLAS routines
`R_ext/Callbacks.h'
C (and R function) top-level task handlers
`R_ext/GetX11Image.h'
X11Image interface used by package @pkg{trkplot}
`R_ext/Lapack.h'
C definitions for some LAPACK routines
`R_ext/Linpack.h'
C definitions for some LINPACK routines, not all of which are included in @R{}
`R_ext/Parse.h'
a small part of @R{}'s parse interface
`R_ext/RConvertors.h'
`R_ext/Rdynload.h'
needed to register compiled code in packages
`R_ext/R-ftp-http.h'
interface to internal method of
download.file
`R_ext/Riconv.h'
interface to
iconv
`R_ext/RStartup.h'
for add-on front-ends
`R_ext/Visibility.h'
definitions controlling visibility
`R_ext/eventloop.h'
for add-on front-ends and for packages that need to share in the @R{} event loops (on all platforms)
The following headers are included by `R.h':
`Rconfig.h'
configuration info that is made available
`R_ext/Arith.h'
handling for
NA
s,NaN
s,Inf
/-Inf
`R_ext/Boolean.h'
TRUE
/FALSE
type`R_ext/Complex.h'
C typedefs for @R{}'s
complex
`R_ext/Constants.h'
constants
`R_ext/Error.h'
error handling
`R_ext/Memory.h'
memory allocation
`R_ext/Print.h'
Rprintf
and variations.`R_ext/Random.h'
random number generation
`R_ext/RS.h'
definitions common to `R.h' and `S.h', including
F77_CALL
etc.`R_ext/Utils.h'
sorting and other utilities
`R_ext/libextern.h'
definitions for exports from `R.dll' on Windows.
The graphics systems are exposed in headers
`R_ext/GraphicsEngine.h', `R_ext/GraphicsDevice.h' (which it
includes) and `R_ext/QuartzDevice.h'. Some entry points from the
@pkg{stats} package are in `R_ext/stats_package.h' (currently
related to the internals of nls
and nlminb
).
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
@R{} programmers will often want to add methods for existing generic functions, and may want to add new generic functions or make existing functions generic. In this chapter we give guidelines for doing so, with examples of the problems caused by not adhering to them.
This chapter only covers the `informal' class system copied from S3, and not with the S4 (formal) methods of package @pkg{methods}.
The key function for methods is NextMethod
, which dispatches the
next method. It is quite typical for a method function to make a few
changes to its arguments, dispatch to the next method, receive the
results and modify them a little. An example is
t.data.frame <- function(x) { x <- as.matrix(x) NextMethod("t") } |
Also consider predict.glm
: it happens that in @R{} for historical
reasons it calls predict.lm
directly, but in principle (and in S
originally and currently) it could use NextMethod
.
(NextMethod
seems under-used in the @R{} sources. Do be aware
that there are S/R differences in this area, and the example above works
because there is a next method, the default method, not that a
new method is selected when the class is changed.)
Any method a programmer writes may be invoked from another method
by NextMethod
, with the arguments appropriate to the
previous method. Further, the programmer cannot predict which method
NextMethod
will pick (it might be one not yet dreamt of), and the
end user calling the generic needs to be able to pass arguments to the
next method. For this to work
A method must have all the arguments of the generic, including
…
if the generic does.
It is a grave misunderstanding to think that a method needs only to
accept the arguments it needs. The original S version of
predict.lm
did not have a …
argument, although
predict
did. It soon became clear that predict.glm
needed
an argument dispersion
to handle over-dispersion. As
predict.lm
had neither a dispersion
nor a …
argument, NextMethod
could no longer be used. (The legacy, two
direct calls to predict.lm
, lives on in predict.glm
in
@R{}, which is based on the workaround for S3 written by Venables &
Ripley.)
Further, the user is entitled to use positional matching when calling
the generic, and the arguments to a method called by UseMethod
are those of the call to the generic. Thus
A method must have arguments in exactly the same order as the generic.
To see the scale of this problem, consider the generic function
scale
, defined as
scale <- function (x, center = TRUE, scale = TRUE) UseMethod("scale") |
Suppose an unthinking package writer created methods such as
scale.foo <- function(x, scale = FALSE, ...) { } |
Then for x
of class "foo"
the calls
scale(x, , TRUE) scale(x, scale = TRUE) |
would do most likely do different things, to the justifiable consternation of the end user.
To add a further twist, which default is used when a user calls
scale(x)
in our example? What if
scale.bar <- function(x, center, scale = TRUE) NextMethod("scale") |
and x
has class c("bar", "foo")
? It is the default
specified in the method that is used, but the default
specified in the generic may be the one the user sees.
This leads to the recommendation:
If the generic specifies defaults, all methods should use the same defaults.
An easy way to follow these recommendations is to always keep generics simple, e.g.
scale <- function(x, ...) UseMethod("scale") |
Only add parameters and defaults to the generic if they make sense in all possible methods implementing it.
| 7.1 Adding new generics |
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |
When creating a new generic function, bear in mind that its argument
list will be the maximal set of arguments for methods, including those
written elsewhere years later. So choosing a good set of arguments may
well be an important design issue, and there need to be good arguments
not to include a …
argument.
If a …
argument is supplied, some thought should be given
to its position in the argument sequence. Arguments which follow
…
must be named in calls to the function, and they must be
named in full (partial matching is suppressed after …
).
Formal arguments before …
can be partially matched, and so
may `swallow' actual arguments intended for …
. Although it
is commonplace to make the …
argument the last one, that is
not always the right choice.
Sometimes package writers want to make generic a function in the base package, and request a change in @R{}. This may be justifiable, but making a function generic with the old definition as the default method does have a small performance cost. It is never necessary, as a package can take over a function in the base package and make it generic by
foo <- function(object, ...) UseMethod("foo") foo.default <- base::foo |
(If the thus defined default method needs a `...' added to its
argument list, one can e.g. use formals(foo.default) <-
c(formals(foo.default), alist(... = ))
.)
The same idea can be applied for functions in other packages with name spaces.
| [ < ] | [ > ] | [ << ] | [ Up ] | [ >> ] | [Top] | [Contents] | [Index] | [ ? ] |