I am trying to write an rbind method for a particular class. Here's a simple example where it doesn't work (at least for me):
rbind.character <- function(...) {
do.call("paste", list(...))
}
After entering this function, I seemingly can confirm that it is a valid method that R knows about:
> methods("rbind")
[1] rbind.character rbind.data.frame rbind.rootogram* rbind.zoo*
see '?methods' for accessing help and source code
However, it is not recognized if I try to use it:
> rbind("abc", "xyz")
[,1]
[1,] "abc"
[2,] "xyz"
> #### compared with ####
> rbind.character("abc", "xyz")
[1] "abc xyz"
The help page says that dispatch is performed internally as follows:
For each argument we get the list of possible class memberships from
the class attribute.
We inspect each class in turn to see if there is an applicable
method.
If we find an applicable method we make sure that it is identical to
any method determined for prior arguments. If it is identical, we
proceed, otherwise we immediately drop through to the default code.
With rbind("abc", "xyz"), I believe all these criteria are satisfied. What gives, and how can I fix it?
attributes("abc")
#NULL
A character vector doesn't have a class attribute. I don't think a method can be dispatched by rbind for the implicit classes.
A workaround would be to define your own class:
b <- "abc"
class(b) <- "mycharacter"
rbind.mycharacter <- function(...) {
do.call("paste", list(...))
}
rbind(b, b)
# [1] "abc abc"
The reason why it does not work with character was nicely explained by Roland in his comment.
rbind is not a standard S3 function, so you cannot "intercept" it for character.
Luckily, you can override the default implementation. Try:
rbind.character <- function(...) {
print("hello from rbind.character")
}
rbind <- function(...) {
args <- list(...)
if (all(vapply(args, is.character, logical(1)))) {
rbind.character(...)
} else {
base::rbind(...)
}
}
Basically, we check if the arguments are all characters. If so, we call our character function. If not, we call the default implementation.
Related
I stacked with trying to pass variable through few functions, and on the final function I want to get the name of the original variable. But it seems like substitute function in R looked only in "local" environment, or just for one level up. Well, let me explain it by code:
fun1 <- function (some_variable) {deparse(substitute(some_variable)}
fun2 <- function (var_pass) { fun1 (var_pass) }
my_var <- c(1,2) # I want to get 'my_var' in the end
fun2 (my_var) # > "var_pass"
Well, it seems like we printing the name of variable that only pass to the fun1. Documentation of the substitute tells us, that we can use env argument, to specify where we can look. But by passing .Global or .BaseNamespaceEnv as an argument to substitute I got even more strange results - "some_variable"
I believe that answer is in this function with using env argument, so, could you please explain me how it works and how can I get what I need. Thanks in advance!
I suggest you consider passing optional name value to these functions. I say this because it seems like you really want to use the name as a label for something in the end result; so it's not really the variable itself that matters so much as its name. You could do
fun1 <- function (some_variable, name=deparse(substitute(some_variable))) {
name
}
fun2 <- function (var_pass, name=deparse(substitute(var_pass))) {
fun1 (var_pass, name)
}
my_var <- c(1,2)
fun2(my_var)
# [1] "my_var"
fun1(my_var)
# [1] "my_var"
This way if you end up having some odd variable name and what to give a better name to a result, you at least have the option. And by default it should do what you want without having to require the name parameter.
One hack, probably not the best way:
fun2 <- function (var_pass) { fun1 (deparse(substitute(var_pass))) }
fun1 <- function (some_variable) {(some_variable))}
fun2(my_var)
# "my_var"
And you could run get on that. But as Paul H, suggests, there are better ways to track variables.
Another approach I'd like to suggest is to use rlang::enexpr.
The main advantage is that we don't need to carry the original variable name in a parameter. The downside is that we have to deal with expressions which are slightly trickier to use.
> fun1 <- function (some_variable) {
message("Entering fun1")
rlang::enexpr(some_variable)
}
> fun2 <- function (var_pass) {
message("Entering fun2")
eval(parse(text=paste0("fun1(", rlang::enexpr(var_pass), ")")))
}
> my_var <- c(1, 2)
> fun1(my_var)
#Entering fun1
my_var
> fun2(my_var)
#Entering fun2
#Entering fun1
my_var
The trick here is that we have to evaluate the argument name in fun2 and build the call to fun1 as a character. If we were to simply call fun1 with enexpr(var_pass), we would loose the notion of fun2's variable name, because enexpr(var_pass) would never be evaluated in fun2:
> bad_fun2 <- function (var_pass) {
message("Entering bad fun2")
fun1(rlang::enexpr(var_pass))
}
> bad_fun2(my_var)
#Entering bad fun2
#Entering fun1
rlang::enexpr(var_pass)
On top of that, note that neither fun1 nor fun2 return variable names as character vectors. The returned object is of class name (and can of course be coerced to character).
The bright side is that you can use eval directly on it.
> ret <- fun2(my_var)
#Entering fun2
#Entering fun1
> as.character(ret)
[1] "my_var"
> class(ret)
[1] "name"
> eval(ret)
[1] 1 2
I need to build a lot of functions with lots of different arguments, though they otherwise share a lot of code and structure.
To avoid duplication, I thought I'd be clever and build myself a function factory (aka closure).
I can't figure out how to pass the function arguments inside the function factory.
My use case is a bunch of S3 constructor functions, all of which share the same validation mechanism.
So I'll use that as an example to explain my problem.
Say, I have a ClassA and ClassB, each of which require their own arguments in the respective constructor functions:
ClassA <- function(A_arg1, A_arg2) {
# some class-SPECIFIC construction magic happens, say
out <- list(A_arg1, A_arg2)
# some GENERAL construction magic happens
class(out) <- "ClassA"
return(out)
}
ClassB <- function(B_arg1, B_arg2) {
# some class-SPECIFIC construction magic happens, say
out <- B_arg1 + B_arg2
# some GENERAL construction magic happens
class(out) <- "ClassB"
return(out)
}
Obviously, I'd love to avoid the duplication in the general part of the constructor functions, so a function factory that could be used like so would be nice:
ClassA <- produce_class_constructor(classname = "ClassA", fun = function(A_arg1, A_arg2) {return(list(A_arg1, A_arg2))})
This should, ideally, yield the exact same function as the above manually constructed ClassA function, with the general part factored out.
Here's my attempt at building that function factory:
produce_class_constructor <- function(classname, fun) {
class_specific_arguments <- formals(fun = fun) # this works just fine on the console
construct_class <- function(class_specific_arguments) {
# here runs the class-specific stuff
out <- fun(class_specific_arguments)
# here runs the general stuff
class(out) <- classname
}
}
This however, does not work, because the resulting constructor function only has a class_specific_arguments-argument, not the, well, actual A_arg1, and A_arg2.
Is there way to do this?
Am I doing this wrong?
(It's really important to me that the resulting class constructor functions have properly named arguments, so a ... approach won't work).
Here's my attempt:
produce_class_constructor <- function(classname, fun) {
out_fun <- function() {
out_obj <- do.call(fun, as.list(environment()))
class(out_obj) <- classname
out_obj
}
formals(out_fun) <- formals(fun)
out_fun
}
ClassA <- produce_class_constructor(classname = "ClassA",
fun = function(A_arg1, A_arg2) {list(A_arg1, A_arg2)})
ClassA(1, 2)
#[[1]]
#[1] 1
#
#[[2]]
#[1] 2
#
#attr(,"class")
#[1] "ClassA"
ClassB <- produce_class_constructor(classname = "ClassB",
fun = function(B_arg1, B_arg2) {B_arg1 + B_arg2})
ClassB(B_arg2 = 2, 1)
#[1] 3
#attr(,"class")
#[1] "ClassB"
Idea with as.list(environment()) taken from this question. Note that you should be extra careful along that path, as ?formals says, "this is
advanced, dangerous coding".
This question already has answers here:
Explain a lazy evaluation quirk
(2 answers)
Closed 7 years ago.
In R, I wanted to create a class (R6Class) that when calling initialize creates few dynamic methods (the number of methods and its names depends on parameters in initialize). But I get into strange problem with environments.
Here is a simplified version of code that doesn't work.
library(R6)
ffactory <- function(i) {
function() i
}
A <- R6Class(
lock_objects=FALSE,
public=list(
initialize=function(args) {
for (i in args) {
self[[i]] <- ffactory(i)
}
}
)
)
a <- A$new(c('a', 'b', 'c'))
Now:
> a$a()
[1] "c"
> a$b()
[1] "c"
> a$c()
[1] "c"
In order to find what was wrong I had added a line that prints environment in ffactory function. That is
ffactory <- function(i) {
print(ls.str())
function() i
}
And now it has started to work!!!
> a$a()
[1] "a"
> a$b()
[1] "b"
> a$c()
[1] "c"
So why? There should be something I don't understand. Observer effect or what? :)
What is the magic of the line print(ls.str())? Actually I cannot remove neither print nor str from this line. Of course it is so silly to have a line like that. Not to mention garbage on the screen.
You have encountered lazy evaluation - R waits as long as it is able to before evaluating i - and in the former case, i will be evaluated at its last value in all instances. There's nothing really special about the combination of print and ls.str; anything that forces i to be evaluated prior to your method calls (a$a(), a$b(), etc...) will do the same.
Formally, this is what force is used for:
ffactory <- function(i) {
force(i);
function() i
}
R> a$a()
#[1] "a"
R> a$b()
#[1] "b"
R> a$c()
#[1] "c"
However, this also happens to do the job:
ffactory <- function(i) {
#force(i);
.z <- capture.output(cat(i, "\n"))
function() i
}
R> a$a()
#[1] "a"
R> a$b()
#[1] "b"
R> a$c()
#[1] "c"
There are presumably countless ways to force evaluation; I would argue that using force makes your intention most clear, though.
Quoting the help file directly,
force forces the evaluation of a formal argument. This can be useful
if the argument will be captured in a closure by the lexical scoping
rules and will later be altered by an explicit assignment or an
implicit assignment in a loop or an apply function.
and subsequently,
This is semantic sugar: just evaluating the symbol will do the same
thing (see the examples).
In fact, looking at how force is defined,
R> force
#function (x)
# x
#<bytecode: 0x3b7b528>
#<environment: namespace:base>
You could even get away with
ffactory <- function(i) {
i; function() i
}
But as noted, I think the explicitly calling force will make your code more readable.
i am trying to create a function in which i want to remove one of the variables passed to it.
now R works in annoying ways in that it copies the object instead of giving a reference.
(technically the copying only happens if you make a change... but meh...)
a=function(b){
rm(b)
# rm(b)
}
test=123
a(test) # will remove b, not test
# you can verify that by adding the 2nd rm(b)
i tried
a=function(b){
rm(match.call()[[2]])
}
but that gives the error:
Error in rm(match.call()[[3]]) :
... must contain names or character strings
Try this:
Foo <- function(x){
Sx <- deparse(substitute(x))
rm(list=Sx,envir=sys.frame(-1))
}
##
Z <- 123
ls()
##
[1] "Foo" "Z"
##
Foo(x=Z)
ls()
[1] "Foo"
similar to nrussell's answer, here's the line from cgwtools::askrm which does an arbitrary function call on the selected object:
call(fn, as.name(thenam)), envir = parent.frame(1))
(and, yes, I'm plugging my own toolkit here :-) )
I would like to pass the value of an object as an argument to a function.
# This is my object
anObject <- "an_unkown_string"
# I would like to do the equivalent of:
someFunc("an_unkown_string")
# .. by somehow calling on the object containing the string
someFunc( ??? (anObject) )
For example, with the sample function below (based on save()):
someFunc <- function(...) {
names <- as.character(substitute(list(...)))[-1L]
return(names)
}
# Ideally, the output would be:
someFunc( ??? (anObject) )
[1] "an_unkown_string"
I do not have access to modify someFunc
I have tried the following, but with no success.
someFunc(Name_of_Object)
someFunc(eval(Name_of_Object))
someFunc(evalq(Name_of_Object))
someFunc(force(Name_of_Object))
someFunc(eval(parse(text=Name_of_Object)))
Any help is appreciated.
How about
> do.call(someFunc, list(anObject))
[1] "an_unkown_string"
Or you could make a wrapper
myWrap <- function(...) {
do.call(someFunc, as.list(...))
}
> myWrap(anObject)
[1] "an_unkown_string"
Another way to construct a call and evaluate it:
> call("someFunc", anObject)
someFunc("an_unkown_string")
> eval(call("someFunc", anObject))
[1] "an_unkown_string"
I suppose I should mention that ?do.call says
The behavior of some functions, such as substitute, will not be the same for functions evaluated using do.call as if they were evaluated from the interpreter. The precise semantics are currently undefined and subject to change.
Nevertheless, for now at least, anObject is evaluated when the call is constructed (in the call to call or do.call), so substitute finds "an_unknown_string" instead of "anObject".
I'm puzzled. Why are you trying to make this more complex than it realy is?
someFunc <- function(obj) {
return(obj)
}
> someFunc(anObject)
[1] "an_unkown_string"