uncool
uncool

Reputation: 2693

How to use the get() function? Making higher hierarchy object accessible as local variable

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

Answers (1)

mra68
mra68

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:

  • The environment env in which the variable v is stored,
  • The name under which the variable 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

Related Questions