I'm studying S4 classes and methods and I got confused to know when to use .Object and object (using as an argument to functions on classes). I don't understand if is there any difference between them.
For example, Would be correct:
setGeneric("getTimes",function(object){standardGeneric ("getTimes")})
setMethod("getTimes","Trajectories",
function(object){
return(object#times)
}
)
or:
setGeneric("getTimes",function(.Object){standardGeneric ("getTimes")})
setMethod("getTimes","Trajectories",
function(.Object){
return(.Object#times)
}
)
First, you should avoid the curly braces around {standardGeneric("getTimes")}.
The short answer for your question: there is no difference between the 2 code in your example. You were defining getTimes as a brand new generic function of your own. You can specify its arguments name whatever you like (object, x, xobject, .Object). Then, when you write the methods for the generic function, your methods' arguments name must match with the generic function's arguments name. For example:
setGeneric("getTimes", function(object) standardGeneric("getTimes"))
setMethod("getTimes", "Trajectories", function(object) object#times)
If not follow, there will be error (technically, a warning because R automatically/"silently" correct it. However, in my opinion, R should stop and throw an error in this case):
setGeneric("getTimes", function(object) standardGeneric("getTimes"))
setMethod("getTimes", "Trajectories", function(x) x#times)
# mismatch between `x` argument name in method and `object` argument name in generic
In the case you want to define methods for existing generic, you should use function method.skeleton.
Example 1:
setGeneric("getTimes", function(xobject) standardGeneric("getTimes")) # generic function is defined
getTimes # type function name without parentheses to get a summary of the generic
method.skeleton("getTimes", "Trajectories", stdout())
# copy this method skeleton to your script/source file and modify to your need
Example 2, show is a predefined generic with object as argument (see ?show) or you can type show without parentheses to check. Therefore, setMethod("show", "Trajectories", function(.Object) .Object) will be error. You can proceed using this approach, however, I think method.skeleton is a pretty useful alternative:
> method.skeleton("show", "Trajectories", stdout())
setMethod("show",
signature(object = "Trajectories"),
function (object)
{
stop("need a definition for the method here")
}
)
Example 3, initialize is a generic function and its argument .Object may be defined (type initialize without parentheses to check). From my understanding, the reason .Object is chosen as argument name in this case to invoke the feeling of a prototype object (you can read more at ?initialize). Similarly to Example 2, use the method.skeleton helper function:
> method.skeleton("initialize", "Trajectories", stdout())
setMethod("initialize",
signature(.Object = "Trajectories"),
function (.Object, ...)
{
stop("need a definition for the method here")
}
)
Note: there is a special case for replacement/assignment function (<-), that is its last argument must be named value. Read more. For example:
setClass("Trajectories", slots = c(times = "numeric"))
setGeneric("getTimes", function(x) standardGeneric("getTimes"))
setMethod("getTimes","Trajectories", function(x) x#times)
setGeneric("getTimes<-", function(xobject, value) standardGeneric("getTimes<-"))
setMethod("getTimes<-", c("Trajectories", "ANY"), function(xobject, value) {
xobject#times <- value
xobject
})
# test drive
m <- new("Trajectories", times = 32)
getTimes(m)
getTimes(m) <- 42
getTimes(m)
R will not output any error or warning if you use other name (new_value in below) when defining the generic and accompanying methods. However, when you use it, R will error:
setGeneric("getTimes<-", function(xobject, new_value) standardGeneric("getTimes<-"))
setMethod("getTimes<-", c("Trajectories", "ANY"), function(xobject, new_value) {
xobject#times <- new_value
xobject
})
# test drive
m <- new("Trajectories", times = 32)
getTimes(m)
getTimes(m) <- 42 # error because the right side of <- is always considered as `value` argument
Related
Sometimes in R a function wants a string or sometimes it wants an object.
For example, rm(x); and rm("x"); work the same.
NOTE: In this example x or "x" is NOT a function. I generically call it an OBJECT. In the example below, I am referring to functions as FN.STR or FN.OBJ, but the QUESTION is looking for a general OBJECT MANIPULATOR. Given a thing, determine if it is a string or object, and return a string/object as requested by the Function. A function then serves as a general API to access R objects.
> rm
function (..., list = character(), pos = -1, envir = as.environment(pos),
inherits = FALSE)
{
dots <- match.call(expand.dots = FALSE)$...
if (length(dots) && !all(vapply(dots, function(x) is.symbol(x) ||
is.character(x), NA, USE.NAMES = FALSE)))
stop("... must contain names or character strings")
names <- vapply(dots, as.character, "")
if (length(names) == 0L)
names <- character()
list <- .Primitive("c")(list, names)
.Internal(remove(list, envir, inherits))
}
<bytecode: 0x00000136a0f22d80>
<environment: namespace:base>
This is useful on this function because the USER doesn't have to remember: do I need the string or object. In fact, you can mix: x=1; y=2; rm(x,"y"); The ... dots have been expended to make this happen... Ideally, it would be nice to save the ... dots for passing parameters through to other functions or for lazy loading like sum allows: sum(1,2,3) == sum(c(1,2,3)). [Or maybe ..1 could be reimagined to allow for multiple dots: ...a, ...b, {ldots}, ...z where the name/order of the ...{letter} would allow lots of match.call magic. Regardless, even this magic is happening in the function, not as a standalone VARIADIC external magicFunction]
Objective
Anyway, I am trying to write a few variadic functions that allow the USER to input either the FUN as fn.str or as fn.obj. At the GLOBAL scope, the following will work:
str.fromObjectName = function(objname)
{
res = deparse(substitute(objname));
res = str.replace('"', "", res);
return(res);
}
WHERE str.replace is a extension of gsub, so for simplicity, let's say:
str.replace = function(search, replace, str)
{
gsub(search, replace, str, fixed=TRUE);
}
So if it is an object, I get the string.name of it (whether or not it actually exists, no error thrown). If it is a string, it has an extra " wrapping it, so the str.replace takes care of that.
As a procedural function, I would like to be able to access this in OTHER functions. But with the nature of the R stack (or my lack of understanding), I can't seem to get it to work. I found a solution in some baseR code that I have applied to use the ... dots to TRAP the potential object. But it has some limitations: I have to use the ... dots so I can't use them for other purposes, and if I call a function from a function the evaluation of the original function name gets lost, so I apply the character.only=FALSE when I call the function INTERNALLY to the other function where at some point the FN.OBJ was converted to FN.STR
So if I review the base packages with character.only I believe the help or library uses it to trap the pkg as a string or object. Maybe the solution is trivial which I am missing, but as I review the base code, it seems like it may be a challenge. It appears the function doesn't know what to do automatically without the character.only flag.
> library
function (package, help, pos = 2, lib.loc = NULL, character.only = FALSE,
...
if (!character.only)
package <- as.character(substitute(package))
...
else if (!missing(help)) {
if (!character.only)
help <- as.character(substitute(help))
...
else invisible(.packages())
}
<bytecode: 0x0000013699060b10>
<environment: namespace:base>
An example
Here is a preamble of one function:
function.info = function(..., character.only=FALSE)
{
if(character.only)
{
fn.str = unlist(list(...));
} else {
fn.str = str.fromObjectName(...);
}
}
NOTE: the ... passthrough allows the GLOBAL function to correctly scope.
This allows the function str "sum" or the function object sum to be inputed into the function (making life BETTER for the user). In the spirit of DRY and VARIADIC programming, it would be nice if I could do this as one external function to function.info ... and allow multiple fn objects to be passed in as parameters that are either the str "sum" or the object sum which INTERNALLY for most purposes I just want the resulting str.
Question
Given a function, how to allow a user to pass multiple FUN elements as either obj/string (mix allowed) using an external function (DRY = don't repeat yourself). In the example, I am referring to FUN.OBJ, but the goal would be to return anything that could be called an OBJ in R, not just a function.
magicFunction = function(FUN.OBJ.OR.STR, return="STR")
{
# do something here ... FUN.OBJ could be any R.OBJ
FUN.AS.STR;
# or if return = "OBJ"
FUN.AS.OBJ
}
v.math = function(data=c("#abcdef","#123456"), FUN, param="hi", FUN.pre="hex2dec", FUN.post=dec2hex)
{
# takes input [whether a str/obj] and returns a string/object.
fn.str = magicFunction(FUN);
fn.pre = magicFunction(FUN.pre);
fn.post = magicFunction(FUN.post);
# get to the main event
}
In the above, "hex2dec" is a string (as in "foo") and dec2hex is an object (as in bar): both referring to functions [something akin to match.fun(base::sum) or match.fun("base::sum"); I think currently it only searches the TOP of the stack.]. I can call my function str.fromObjectName on them in the GLOBAL sphere and get what I want, but when placed inside another function, it will return something else. I did a bunch of sys.call VOODOO that I didn't understand fully, and it would allow it to work at one-level deep of function calls (I guess because of the nature of the call stack). And it would only work on have one FUN to evaluate in the v.math where I have 3 functions to evaluate.
Here's a wrapper around match.fun to allow for the user to include :: in a string argument:
as_fun = function(x) {
if(is.character(x) && grepl("::", x)) return(eval(parse(text = x)))
match.fun(x)
}
as_fun(base::sum)
# function (..., na.rm = FALSE) .Primitive("sum")
as_fun("base::sum")
# function (..., na.rm = FALSE) .Primitive("sum")
as_fun(sum)
# function (..., na.rm = FALSE) .Primitive("sum")
as_fun("sum")
# function (..., na.rm = FALSE) .Primitive("sum")
I am trying to understand the behaviour of user-defined functions like the below (based on the first answer to this question), which returns the arguments supplied to it as a named list:
function(a, b, ...) {
argg <- c(as.list(environment()), list(...))
print(argg)
}
Essentially, functions like the above produce unexpected behaviour when one of the argument names is also the name of a primitive function whose only parameter is ...
Below are some reproducible examples.
Example 1 - function behaves as expected, missing argument does not cause error
#define function as above
fun1 <- function(a, b, ...) {
argg <- c(as.list(environment()), list(...))
print(argg)
}
#run function
fun1(a = 1)
#returns the below. note that $b has the missing argument and this does not cause an error
#$a
#[1] 1
#$b
Example 2 - function returns error if 'c' is one of the explicit parameters and missing
#define function as above but with new explicit argument, called 'c'
#note that c() is a primitive function whose only parameter is ...
fun2 <- function(a, b, c, ...) {
argg <- c(as.list(environment()), list(...))
print(argg)
}
#run function
fun2(a = 1)
#returns error:
#Error in c(as.list(environment()), list(...)) :
# argument "c" is missing, with no default
Example 3 - replace 'c' with 'switch', a primitive function with parameters other than ...
#define function same way as fun2, but change 'c' parameter to 'switch'
#note that switch() is a primitive function that has parameters other than ...
fun3 <- function(a, b, switch, ...) {
argg <- c(as.list(environment()), list(...))
print(argg)
}
#run function
fun3(a = 1)
#returns the below. note that $b and $switch have the missing argument and this does not cause an error
#$a
#[1] 1
#$b
#$switch
I have tried numerous variations of the above that seem pointless to print here given that the basic pattern should be clear and thus easily reproducible without specific passages of code; suffice to say that as far as I have been able to tell, it appears that the function returns an error if one of its arguments a.) has the same name as a primitive function whose only parameter is ... and b.) is also missing. No other changes that I tested (such as removing the ... from the user-defined function's parameters; altering the order in which the arguments are specified when calling the function or when defining the function; changing the names and quantity of other arguments specified when calling the function or defining the function, etc.) had an impact on whether the behaviour was as expected.
Another point to note is that I don't see an error if I define a function with the same parameters as fun2, and with the c argument still missing, if I am not trying to access the function's arguments inside it. For example:
#define function with same parameters but different content to fun2
fun4 <- function(a, b, c, ...) {
return(a+b)
}
#run function
fun4(a = 1, b = 2)
#returns
#[1] 3
Please could somebody explain why I see this pattern of behaviour and the reason for the key role apparently played by primitive functions that only have ... as a parameter.
Please do not submit answers or comments suggesting 'workarounds' or querying the practical significance of the issue at hand. I am not asking my question in order to address a specific practical problem and there is no reason I can think of why I would ever be forced to use the name of a primitive function as a parameter; rather, I want to understand why the errors occur when they do in order to gain a clearer understanding of how functions in general, and the processes used to access their parameters in particular, work in R.
It's not the ... that's causing the problem. When you call c(), R looks for the function definition in the environment. Outside of a function it will normally find this as base::c. But within your function it first looks for the definition in the argument c in the function call, which it then can't find. This way of calling shows that it can work by telling R specifically where to find the definition of c:
fun4 <- function(a, b, c, ...) {
argg <- base::c(as.list(environment()), list(...))
print(argg)
}
#run function
fun4(a = 1)
#> $a
#> [1] 1
#>
#> $b
#>
#>
#> $c
Environments - from Advanced R
To demonstrate where things are being called you can use this tip from Advanced R by Hadley Wickham to see where R is finding each object. In the function where c isn't an argument, it finds it in base, otherwise it "finds" it in the function environment (where a and b are also defined):
library(rlang)
where <- function(name, env = caller_env()) {
if (identical(env, empty_env())) {
stop("Can't find ", name, call. = FALSE)
} else if (env_has(env, name)) {
env
} else {
where(name, env_parent(env))
}
}
fun5 <- function(a, b, ...) {
print(where("a"))
print(where("b"))
print(where("c"))
}
#run function
fun5(a = 1)
#> <environment: 0x000000001de35890>
#> <environment: 0x000000001de35890>
#> <environment: base>
fun6 <- function(a, b, c, ...) {
print(where("a"))
print(where("b"))
print(where("c"))
}
#run function
fun6(a = 1)
#> <environment: 0x000000001e1381f0>
#> <environment: 0x000000001e1381f0>
#> <environment: 0x000000001e1381f0>
Created on 2021-12-15 by the reprex package (v2.0.1)
I have a generic function foo that I want to call three different ways depending on the arguments given to it.
foo <- function(...) UseMethod("foo")
#default
foo.default <- function(x, y, ...) {
#does some magic
print("this is the default method")
}
#formula
foo.formula <- function(formula, data = list(), ...) {
print("this is the formula method")
}
#data.frame
foo.data.frame <- function(data, x, y, ...) {
print("this is the data.frame method")
}
In the following I'm going to show how I am expecting the method dispatch to work but the outputs are presented under each call...
mydata <- data.frame(x=c(1,2,3,4),y=c(5,6,7,8))
#ways to call default function
foo(x = mydata$x, y = mydata$y)
#[1] "this is the default method"
#ways to call formula
foo(formula = mydata$x~mydata$y)
#[1] "this is the formula method"
foo(formula = x~y, data = mydata)
#[1] "this is the formula method"
foo(data = mydata, formula = x~y) #ERROR
#[1] "this is the data.frame method"
#ways to call data.frame method
foo(data = mydata, x = x, y = y)
#[1] "this is the data.frame method"
foo(x = x, y = y, data = mydata) #ERROR
#Error in foo(x = x, y = y, data = mydata) : object 'x' not found
from what I can tell, the method used depends on the class of the first argument. Essentially, I would like for the method dispatch to depend on the arguments passed to the generic function foo and not the first argument.
I would like the dispatch to have the following priority:
If the formula argument is present the formula method is used (data argument should be optional here)
Then, if no formula argument is found, if data argument is present use data.frame method (which requires x and y arguments)
else foo expects the x and y arguments or it will fail.
Note
I would like to avoid defining the generic function foo as follows
foo <- function(formula, data,...) UseMethod("foo")
while this would fix all my issues (I believe all except the last case), this will cause a devtools::check() warning because the some of S3 functions will not have the same arguments as the generic function and will no longer be consistent (specifically foo.default and foo.data.frame). And I wouldn't like to include the missing arguments because those methods do not have use for those arguments.
As Thomas has pointed out, this is not the standard behavior for S3 classes. If you really want to stick to S3, however, you could write your functions so as to "mimick" UseMethod, even though it won't be pretty and is probably not what you want to do. Nevertheless, here an idea that is based on capturing all arguments first, and then checking for the presence of your "preferred" argument type:
Get some objects first:
a <- 1; class(a) <- "Americano"
b <- 2; class(b) <- "Espresso"
Let the function in question capture all arguments with dots, and then check for the presence of an argument type in order of your preference:
drink <- function(...){
dots <- list(...)
if(any(sapply(dots, function(cup) class(cup)=="Americano"))){
drink.Americano(...)
} else { # you can add more checks here to get a hierarchy
# try to find appropriate method first if one exists,
# using the first element of the arguments as usual
tryCatch(get(paste0("drink.", class(dots[[1]])))(),
# if no appropriate method is found, try the default method:
error = function(e) drink.default(...))
}
}
drink.Americano <- function(...) print("Hmm, gimme more!")
drink.Espresso <- function(...) print("Tripple, please!")
drink.default <- function(...) print("Any caffeine in there?")
drink(a) # "Americano", dispatch hard-coded.
# [1] "Hmm, gimme more!"
drink(b) # "Espresso", not hard-coded, but correct dispatch anyway
# [1] "Tripple, please!"
drink("sthelse") # Dispatches to default method
# [1] "Any caffeine in there?"
drink(a,b,"c")
# [1] "Hmm, gimme more!"
drink(b,"c", a)
# [1] "Hmm, gimme more!"
While constructing a function I discovered, that complex numbers are disjoint when setting the function body:
funCplx <- function () {}
formals(funCplx) <- alist(t=)
body(funCplx) <- as.call(c(as.name("{"), parse(text = "t*(2+3i)")))
funCplx
funCplx(3)
As you can see, the function returns the correct value, but contains t * (2+(0+3i)). It is disjoint within the c(). The expression c(parse(text = "t*(2+3i)")) returns the disjoint term, whereas parse(text = "t*(2+3i)") returns t*(2+3i).
Why is the expression disjoint in the body?
Edit: I add an argument to the function. I removed it for sparseness, but it gets necessary to get the correct solution.
Edit 2: Most answers assume I know the complex number (here 2+3i). I took this example, because it is minimal.
In my real case, I take many complex numbers from variable matrices and put them together in one function with additional variables (here t) and functions like exp. In my first step I paste different parts and parse this text into the function body.
To point out my question: Is it bad that the complex number is disjoint in the parse function in case of calculation steps? Reworded: Does R need more calculation steps to calculate 5*(2+(0+3i)) than 5*(2+3i)?
Why not:
funCplx <- function () {}
formals(funCplx) <- alist()
body( funCplx) <- as.call(c(as.name("{"), eval(parse(text = "2+3i"))) )
funCplx
funCplx()
Returns:
funCplx
#----console displays---
function ()
{
2+3i
}
With the added request to include extra arguments in what appears when the function is print-ed, you could make it look more "finished" by assigning the fixed value to a name and then using that name in the expression:
funCplx <- function () {}
formals(funCplx) <- alist(t=)
environment(funCplx) <- new.env()
environment(funCplx)$cplx <- (2+3i)
body(funCplx) <- quote(t*cplx)
funCplx
# function (t)
# t * cplx
funCplx(3)
# [1] 6+9i
And testing to see if the earlier flimsy construction error was fixed:
> cplx=42
> funCplx(7)
[1] 14+21i
The earlier method didn't create an environment for funCplx and so its environment was .GlobalEnv. This version will carry 'cplx' around with it.
To create an expression that multiplies an argument by a given complex constant, use this:
funCplx <- function () {}
formals(funCplx) <- alist(t=)
body(funCplx) <- as.call(c(as.name("{"), call("*", as.symbol("t"), 2+3i)))
funCplx
funCplx(3)
Note that this avoids evaluation of 2 + (0+3i) at "run-time", since the constant is "hard-coded" in the function's body:
> body(funCplx)[[2]][[3]]
[1] 2+3i
> is(body(funCplx)[[2]][[3]])
[1] "complex" "vector"
Suppose we have this functions in a R package.
prova <- function() {
print(attr(prova, 'myattr'))
print(myattr(prova))
invisible(TRUE)
}
'myattr<-' <- function(x, value) {
attr(x, 'myattr') <- value
x
}
myattr <- function(x) attr(x, 'myattr')
So, I install the package and then I test it. This is the result:
prova()
# NULL
# NULL
myattr(prova) <- 'ciao' # setting 'ciao' for 'myattr' attribute
prova()
# NULL
# NULL # Why NULL here ?
myattr(prova)
# [1] "ciao"
attr(prova, 'myattr')
# [1] "ciao"
The question is: how to get the attribute of the function from within itself?
Inside the function itself I cannot get its attribute, as demonstrated by the example.
I suppose that the solution will be of the serie "computing on the language" (match.call()[[1L]], substitute, environments and friends). Am I wrong?
I think that the important point here is that this function is in a package (so, it has its environment and namespace) and I need its attribute inside itself, in the package, not outside.
you can use get with the envir argument.
prova <- function() {
print(attr(get("prova", envir=envir.prova), 'myattr'))
print(myattr(prova))
invisible(TRUE)
}
eg:
envir.prova <- environment()
prova()
# NULL
# NULL
myattr(prova) <- 'ciao'
prova()
# [1] "ciao"
# [1] "ciao"
Where envir.prova is a variable whose value you set to the environment in which prova is defined.
Alternatively you can use get(.. envir=parent.frame()), but that is less reliable as then you have to track the calls too, and ensure against another object with the same name between the target environment and the calling environment.
Update regarding question in the comments:
regarding using parent.frame() versus using an explicit environment name: parent.frame, as the name suggests, goes "up one level." Often, that is exactly where you want to go, so that works fine. And yet, even when your goal is get an object in an environment further up, R searches up the call stack until it finds the object with the matching name. So very often, parent.frame() is just fine.
HOWEVER if there are multiple calls between where you are invoking parent.frame() and where the object is located AND in one of the intermediary environments there exists another object with the same name, then R will stop at that intermediary environment and return its object, which is not the object you were looking for.
Therefore, parent.frame() has an argument n (which defaults to 1), so that you can tell R to begin it's search at n levels back.
This is the "keeping track" that I refer to, where the developer has to be mindful of the number of calls in between. The straightforward way to go about this is to have an n argument in every function that is calling the function in question, and have that value default to 1. Then for the envir argument, you use: get/assign/eval/etc (.. , envir=parent.frame(n=n) )
Then if you call Func2 from Func1, (both Func1 and Func2 have an n argument), and Func2 is calling prova, you use:
Func1 <- function(x, y, ..., n=1) {
... some stuff ...
Func2( <some, parameters, etc,> n=n+1)
}
Func2 <- function(a, b, c, ..., n=1) {
.... some stuff....
eval(quote(prova()), envir=parent.frame(n=n) )
}
As you can see, it is not complicated but it is * tedious* and sometimes what seems like a bug creeps in, which is simply forgetting to carry the n over.
Therefore, I prefer to use a fixed variable with the environment name.
The solution that I found is:
myattr <- function(x) attr(x, 'myattr')
'myattr<-' <- function(x, value) {
# check that x is a function (e.g. the prova function)
# checks on value (e.g. also value is a function with a given precise signature)
attr(x, 'myattr') <- value
x
}
prova <- function(..., env = parent.frame()) {
# get the current function object (in its environment)
this <- eval(match.call()[[1L]], env)
# print(eval(as.call(c(myattr, this)), env)) # alternative
print(myattr(this))
# print(attr(this, 'myattr')
invisible(TRUE)
}
I want to thank #RicardoSaporta for the help and the clarification about keeping tracks of the calls.
This solution doesn't work when e.g. myattr(prova) <- function() TRUE is nested in func1 while prova is called in func2 (that it's called by func1). Unless you do not properly update its parameter env ...
For completeness, following the suggestion of #RicardoSaporta, I slightly modified the prova function:
prova <- function(..., pos = 1L) {
# get the current function object (in its environment)
this <- eval(match.call()[[1L]], parent.frame(n = pos)
print(myattr(this))
# ...
}
This way, it works also when nested, if the the correct pos parameter is passed in.
With this modification it is easier to go to fish out the environment in which you set the attribute on the function prova.
myfun1 <- function() {
myattr(prova) <- function() print(FALSE)
myfun2(n = 2)
}
myfun2 <- function(n) {
prova(pos = n)
}
myfun1()
# function() print(FALSE)
# <environment: 0x22e8208>