1

I am trying to understand the difference between <- and <<- in practice. I wrote the following function in R that relies on a couple of other small function that I wrote:

fun.exec <- function(x=dat){
  id1 <- prompt1()
  id2 <- prompt2()
  el.type <- data.switch(di=id1)
  dat.sifted <- data.sift(x, nc=id2)
  plots.list <- evol.tiles(ds=dat.sifted, dt=el.type, nc=id2)
  p <- evol.plot(l=plots.list, dt=el.type)
}

Functions prompt1 and prompt2 take an input from a user, el.type() assigns string name to the data (for use in describing different plots automatically), data.sift() extract relevant data from a big data frame object, evol.tiles() generates various ggplots to be organized in a grid, and evol.plot() puts the plots in a grid.

As can be seen, both data.sift() and evol.tiles() functions use the id2 user's input. When I execute this function as is, I get an error:

Error in evol.tiles(ds = dat.sifted, dt = el.type, nc = id2) : object 
'id2' not found 

If I replace id2 <- prompt2() with id2 <<- prompt2(), the code works as expected.

What I don't understand is why, as is, the code does not break on the data.sift() function, which also calls for id2. I read help for assignments, a couple of related posts on StackOverflow, and the Scope section from An Introduction to R but I am still not sure what the problem is. It's almost as if after being used in data.sift() the variable was no longer available in the environment and I don't understand that is.

Any help will be greatly appreciated.

UPDATE: Here is the code for prompts:

prompt1 <- function(){
  cat('What do you want to create plots for? Your options are:
        1: data type A,
        2: data type B,
        3: data type C')
  readline(prompt="Enter an integer: ")
}

prompt2 <- function(){
  cat('How many nodes do you want to visualize?')
  n <- readline(prompt="Enter an integer: ")
  cat('\nProvide coordinates of each node to visualize separated by commas.')
  l <- vector("list", n)
  for (i in 1:n){
    el <- readline(prompt=paste('Enter coordinnates for node',i,': '))
    l[[i]] <- el
  }
  return(l)
}

for data.sift():

data.sift <- function(x, nc){
  nl <- lapply(nc, function(l){as.integer(unlist(strsplit(l,",")))})
  ds <- vector("list", length(nl))
  for (i in 1:length(nl)){
    ds[[i]] <- x[(x$x == nl[[i]][1] & x$y == nl[[i]][2] & x$z == nl[[i]][3]),]
  }
  return(ds)
}

and for evol.tiles():

evol.tiles <- function(ds, dt, nc){
  require(ggplot2)
  my.cols <- rainbow(length(ds))
  my.names <- as.character(nc)
  names(my.cols) <- my.names

  my.list <- list()
  for (i in 1:6){
    for (ii in 1:length(id2)){
      p <- ggplot(NULL, aes_(x = as.name(names(ds[[ii]][4]))))
      p <- p + geom_line(data = ds[[ii]], 
                         aes_(y = as.name(names(ds[[ii]][i])), 
                              colour = as.character(nc[[ii]])))
    }
    p <- p  + scale_colour_manual("Node",
                          breaks = as.character(nc),
                          values = my.cols)
    my.list[[i-dr[1]+1]] <- p
  }
  return(my.list)
}
Justyna
  • 737
  • 2
  • 10
  • 25
  • 10
    "I am trying to understand the difference between <- and <<- in practice". I would say that in practice -- don't use `<<-` at all. – John Coleman Jul 05 '18 at 12:22
  • 2
    This is really curious. I don't think you should be using `<<-`, but it is very weird that you get that error. `id2` should definitely be available. Not sure how to figure this out without seeing more code. Anything weird you are doing in `data.sift` or `evol.tiles`? – Axeman Jul 05 '18 at 12:27
  • 1
    It might be due to `ggplot`s dealing with variables/environments. You could try if the problem is resolved with installing the latest ggplot version. – Axeman Jul 05 '18 at 12:29
  • This question may have been closed too quickly. I agree with @Axeman that it is not evident why `id2` goes out of scope here. – RHertel Jul 05 '18 at 12:31
  • I'd say this should be reopened, but we would probably need to have a look at your functions and some example data to reproduce the error. – LAP Jul 05 '18 at 12:34
  • Where do the `prompt1()` and `prompt2()` functions come from? Without having the details, it is hard to judge where your problem comes from. – Jaap Jul 05 '18 at 12:34
  • Another possibility is that `data.sift` never actually uses the `nc` argument, in which case it isn't evaluated and no error is given.. – Axeman Jul 05 '18 at 12:35
  • 2
    Please update your question with all necessary info, so we can have a better look at what the problem might be. Now it is just a guessing game. [See also the info on how to give a reproducible example](http://stackoverflow.com/questions/5963269/how-to-make-a-great-r-reproducible-example/5963610). – Jaap Jul 05 '18 at 12:36
  • 4
    This is one of those cases where the question in the title is a clear duplicate (and arguably, should be closed as such) but the body of the question involves something which isn't a duplicate. I am willing to vote to reopen it, but think that the title should be changed to reflect the actual question (which itself should be expanded to include a [mcve]). – John Coleman Jul 05 '18 at 12:40
  • 2
    Try to post the different functions and strip out all the code that isn't necessary to reproduce the problem. Then give the simplest dataset to reproduce. Right now it's just a guessing game, and the question may be closed again for not being reproducible. – Axeman Jul 05 '18 at 12:49
  • @Axeman I have the latest version of ggplot. I added the code for `data.sift()' and `evol.tiles()` if that helps. – Justyna Jul 05 '18 at 12:58
  • It doesn't hurt, but it's still very hard to debug if we can't reproduce on our end. – Axeman Jul 05 '18 at 13:02
  • @Axeman I'll add a sample data frame in a sec. – Justyna Jul 05 '18 at 13:03
  • Your `evol.tiles()` function uses a variable (in the inner loop index) that isn't defined anywhere in the code that you show: `id.node`. Where does that come from? – Mikko Marttila Jul 05 '18 at 13:11
  • 1
    Again, please remove _everything_ which is not related to your actual issue. – Henrik Jul 05 '18 at 13:14
  • I am working on it right now. I'll post a minimal working example as soon as I get it to reproduce my error. – Justyna Jul 05 '18 at 13:27
  • 1
    I think I found the issue - as I was trying to generate the working example I discovered that in my function `evol.tiles()` I was calling the `id2` variable instead of `nc` (in the inner loop). @Mikko Marttila: thank you for pointing to that! I guess when I used `<<-` for `prompt2()` I was assigned globally and it could be found when called within `evol.tiles()` but with `<-` it was not available to `evol.tiles()`. Is that what happened? – Justyna Jul 05 '18 at 13:57
  • I guess I thought that the function would look in the parenting environment for the missing arguments since the `id2` was defined within `fun.exec` the `time.evol()` would be able to find the right value. – Justyna Jul 05 '18 at 14:09
  • Here is a simple example showing how I would expect the code to behave, even with an incorrectly named variable as it was in my case: if I run function `test <- function(){x*x}`, I get the same error as with my function, i.e., `Error in test() : object 'x' not found`. However, if I run `x<-2` and then `test()`, the output is `[1] 4`. Could someone tell me why wasn't my function behaving in the same way? – Justyna Jul 05 '18 at 16:12

1 Answers1

0

As posted in the comments, I think I found the issue - while working on a minimal working example I discovered that in my function evol.tiles() I was calling the id2 variable instead of nc (in the inner loop). I guess when I used <<- for prompt2() I was assigned it globally and then it could be found when called from within evol.tiles() but with <- it was not available to evol.tiles().

Even so, I still don't quite understand why was that happening. I would think that that the function should look in the parenting environment for the missing arguments and since the id2 was defined within fun.exec(), the time.evol() should be able to find the right value.

Here is a simple example showing how I would expect the code to behave, even with an incorrectly named variable as it was in my case:

test <- function(){x*x}
test()
Error in test() : object 'x' not found

If I run the test() function on its own, I get the same error as with my function, whic is what I would expect. However, if I assign value to x, i.e.,

x <- 2
test()
[1] 4 

the function works just fine. Could someone tell me why wasn't my function behaving in the same way?

UPDATE: @Aaron: The example you gave, i.e., rm(x); test2 <- function() { x <- 2; test() }; test2(), executes for me just fine:

enter image description here

So I still don't understand what the issue is. Any thoughts?

Justyna
  • 737
  • 2
  • 10
  • 25
  • 1
    Hi Justyna, I think it's probably best at this point to close this question and open a new one, this one has a lot of baggage that you've discovered isn't important to the question at hand. If you choose to do that, there's one more piece of a MCVE I think you'd need; namely, that inside another function, `test` doesn't do what you expect after assigning `x`, like this: `rm(x); test2 <- function() { x <- 2; test() }; test2()` – Aaron left Stack Overflow Jul 05 '18 at 16:52
  • Actually, I think that question is a duplicate of https://stackoverflow.com/q/18338331/210673; though the answer there is fairly technical. Or maybe https://stackoverflow.com/q/44427752/210673; that question isn't as similar, but the answer I think might be a better fit. In particular, it's looking in the enclosing environment, not the parent environment. – Aaron left Stack Overflow Jul 05 '18 at 17:02
  • @Aaron Thank you for the references. Both posts and the references within are really helpful! I don't think I need to post a new question about it. Thank you again! – Justyna Jul 07 '18 at 00:16