Reputation: 2693
I have some code below. Now I would want to manipulate my initial top level x
variable when an error occurs in the tryCatch
statement. I read the documentation, but I can't really figure out how it's supposed to be used.
Some questions I can't get my head around.
What is the workflow for these type of issues? (Should I define a new enviroment for the x
variable and reference that enrivoment when I want x
in my local function?
How to use the get() function? I suppose for my task I need the get() function, coupled with the superassignment operator <<-
or assign
.
Something like. x <<- x[! x %in% get(x, envir = "no idea")]
is what I need.
You can try out the code by specifying any vector with valid yahoo tickers, such as LoadData(c('YHOO', 'GOOG'))
. The tryCatch
statement is meant to catch any tickers that do not exist, and in that case I want to modify my initial ticker list (the x
variable) to not include this ticker name. Thus the need for an get()
operation.
LoadData <- function(x) {
if(is.atomic(x) != TRUE & is.data.frame(x) != TRUE) stop('x must be either a data.frame or an atomic object')
if(is.data.frame(x) == TRUE) x <- as.character(x[,1])
df.list <- lapply(x, function(x) {
poss.error <- tryCatch(
{
quantmod::getSymbols(x, env = NULL, return.class = 'data.frame')
},
error = function(e) {
message(cat(x, "could not be retrieved"))
# Get the x variable that was passed to LoadData() and manipulate it.
return(e)
})
}
Upvotes: 2
Views: 79
Reputation: 2960
In the function call LoadData(c('YHOO', 'GOOG'))
mentioned in your question, the argument x
is not a variable but simply a value. If the value is first stored in a variable, e.g. v
, then the value of this variable can be altered by the function. (v
is the "global" name outside the function, x
is the name inside the function.)
Now consider the function call LoadData(x=v)
or simply LoadData(v)
. To get the variable v
from inside the function, two things are needed:
env
in which the variable v
is stored,v
is stored in the environment env
.The environment env
should be another argument of the function LoadData
, perhaps with the global environment as default value:
LoadData <- function(x,env=.GlobalEnv) { ... }
The trick to get the name of the variable passed to the argument x
is to use the function match.call
. as.list(match.call())
is a named list and as.list(match.call())$x
is the "symbol" that is passed to the argument x
, i.e. "v" in our case. Then
x.name <- as.character(as.list(match.call())$x`)
is the desired name of the variable passed to the argument x
.
Now you can use env[[x.name]]
to alter the value of v
. The value of v
is get(x.name,env)
, but this is the same as the value of x
. So get
is not really needed.
Here is a small example:
f <- function( x, v, env=.GlobalEnv )
{
x.name <- as.character(as.list(match.call())$x)
if ( !is.numeric(x) ) { stop(paste0(x.name," must be numeric")) }
env[[x.name]] <- x-v
return(NULL)
}
.
> x <- 5
> y <- 3
> z <- "abc"
> f(x,1)
NULL
> x
[1] 4
> f(y,2)
NULL
> y
[1] 1
> f(z,3)
Error in f(z, 3) : z must be numeric
>
If f
is called from another function g
to alter the value of a local variable a
, the argument env
has to be used:
g <- function()
{
a <- 10
print("global environment:")
print(ls(.GlobalEnv))
print("local environment:")
print(ls(environment()))
print("value of `a` before calling `f`:")
print(a)
f(a,1,environment())
print("value of `a` after calling `f`:")
print(a)
return(NULL)
}
.
> g()
[1] "global environment:"
[1] "f" "g" "x" "y" "z"
[1] "local environment:"
[1] "a"
[1] "value of `a` before calling `f`:"
[1] 10
[1] "value of `a` after calling `f`:"
[1] 9
NULL
If the variable passed to LoadData
is always the same variable and stored in the global environment, LoadData
doesn't need any argument. Then you can simply use <<-
.
Upvotes: 2