Dear folks, I?m trying to build a function to create and make available some variables I frequently use for testing purposes. Suppose I have a function that takes some inputs and creates (internally) several named objects. Say, fun1 <- function(x, y, z) {obj1 <- x; obj2 <- y; obj3 <- z <missing stuff> } Here is the challenge: After I run it, I want the objects to be available in the calling environment, but not necessarily in the global environment. I want them to be individually available, not as part of a list or some larger object. I can not figure out how to do this. If I understand the situation correctly, I am trying to move several separate objects from the environment of the function to the environment in which the function was invoked (the ?calling environment,? yes?). I?m pretty sure there is a command to do this, but I?m not sure how to find it. Any help would be greatly appreciated ? either on the necessary code, or on how to search for it, or a reference to a good discussion of this family of problems. Sincerely, andrewH -- View this message in context: http://r.789695.n4.nabble.com/reporting-multiple-objects-out-of-a-function-tp3873380p3873380.html Sent from the R help mailing list archive at Nabble.com.
On 10/05/2011 04:27 AM, andrewH wrote:> Dear folks, > > I?m trying to build a function to create and make available some variables I > frequently use for testing purposes. Suppose I have a function that takes > some inputs and creates (internally) several named objects. Say, > > fun1 <- function(x, y, z) {obj1 <- x; obj2 <- y; obj3 <- z > <missing stuff> > } > > Here is the challenge: After I run it, I want the objects to be available in > the calling environment, but not necessarily in the global environment. I > want them to be individually available, not as part of a list or some larger > object. I can not figure out how to do this. If I understand the situation > correctly, I am trying to move several separate objects from the environment > of the function to the environment in which the function was invoked (the > ?calling environment,? yes?). > > I?m pretty sure there is a command to do this, but I?m not sure how to find > it. Any help would be greatly appreciated ? either on the necessary code, or > on how to search for it, or a reference to a good discussion of this family > of problems. > > Sincerely, andrewH > > > -- > View this message in context: http://r.789695.n4.nabble.com/reporting-multiple-objects-out-of-a-function-tp3873380p3873380.html > Sent from the R help mailing list archive at Nabble.com. > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.Hi, You can use the <<- operator. Although in the spirit of fortune(106), "If <<- is the answer, rethink your question...". Why is it important that your objects are not part of a larger object, which is standard practice in R. You could also take a look at the attach() command: bla = fun1(x,y,z) attach(bla) Note that in fun1 you do need to return your objects in a list. However, I'm still not in favor of using this approach... good luck, Paul -- Paul Hiemstra, Ph.D. Global Climate Division Royal Netherlands Meteorological Institute (KNMI) Wilhelminalaan 10 | 3732 GK | De Bilt | Kamer B 3.39 P.O. Box 201 | 3730 AE | De Bilt tel: +31 30 2206 494 http://intamap.geo.uu.nl/~paul http://nl.linkedin.com/pub/paul-hiemstra/20/30b/770
Hi Andrew I am not sure if I understood your question entirely. You want to store some objects, but not in the global environment. Correct?! I would do it like this (although I am sure that there is a more elegant way to do this). ## ---------------------------------------------------------------- obj1 <- 2 attach(what = NULL, name = "my_env") ##?create new environment assign("obj1", obj1, envir = as.environment("my_env")) ## assign obj1 to new environment rm(list = ls()) ##?remove all objects from global environment obj1 ##?still available ls("my_env") ##?still available in environment "my_env" ## ---------------------------------------------------------------- Regards, Sina -- View this message in context: http://r.789695.n4.nabble.com/reporting-multiple-objects-out-of-a-function-tp3873380p3875488.html Sent from the R help mailing list archive at Nabble.com.
Thanks for the response, Paul! But I thought these dumped the variables into the global environment. Is that not correct? I want to make them available in the calling environment, without making them available in the global environment, unless that is where the function is called. This is my bow to the fact that what I want this function to do is not good programming practice in general. The whole purpose of this function is to save me time, typing and wear on my limited short-term memory capacity, by having standard objects with standard names quickly available. I wonder if eval.parent would do the job. Like: fun1 <- function(x, y, z) eval.parent{obj1 <- x; obj2 <- y; obj3 <- z }) Or does that just use the parent environment for the inputs, not the output? Part of my problem is that I am not sure how to tell if I have succeeded. Otherwise I would just test it myself. andrewH -- View this message in context: http://r.789695.n4.nabble.com/reporting-multiple-objects-out-of-a-function-tp3873380p3875586.html Sent from the R help mailing list archive at Nabble.com.
Thanks, Sina! This is very helpful and informative, but still not quite what I want. So, here is the thing: When a function returns an object, that object is available in the calling environment. If it is returned inside a function, it is available in the function, but not outside of the function. What I want to do is simply to return more than one object in the usual sense in which functions return objects. Here is a test to see if a function fun does this, at least to the depth of 1. obj1 <- 1 obj2 <- 2 cat("obj1 in global=", obj1) cat("obj2 in global=", obj2) wrapFun <- function(fun) { obj1 <- 3 obj2 <- 4 cat("obj1 in calling=", obj1) cat("obj2 in calling=", obj2) fun() cat("obj in calling=", obj) cat("obj1 in calling=", obj1) cat("obj2 in calling=", obj2) } cat("obj1 in global=", obj1) cat("obj2 in global=", obj2) Suppose the function "fun" assigns the values 5 and 6 to obj1 and obj2. If the function does what I want, this code should print: obj1 in global= 1 obj2 in global= 2 obj1 in calling= 3 obj2 in calling= 4 obj1 in calling= 5 obj2 in calling= 6 obj1 in global= 1 obj2 in global= 2 I turned Paul?s and Sina?s code into functions as follows: paulFun <- function() { obj1 <<- 5; obj2 <<- 6; } sinaFun <- function() { attach(what = NULL, name = "my_env") assign("obj1", 5, envir = as.environment("my_env")) assign("obj1", 5, envir = as.environment("my_env")) } Running these two functions in the code above yields: paulFun: obj1 in global= 1 obj2 in global= 2 obj1 in calling= 3 obj2 in calling= 4 obj1 in calling= 3 obj2 in calling= 4 obj1 in global= 5 obj2 in global= 6 So paulFun puts the objects in the global environment but not in the calling environment. Let?s try sinaFun: sinaFun: obj1 in global= 1 obj2 in global= 2 obj1 in calling= 3 obj2 in calling= 4 obj1 in calling= 3 obj2 in calling= 4 obj1 in global= 1 obj2 in global= 2 sinaFun puts the objects in the new environment it defines, but they are available in neither the calling nor the global environment. However, I was immediately convinced that Sina had given me the tool I was missing: the assign function. (Thanks, Sina!) But I was wrong (or used it wrong), and now I am even more deeply confused. Here is a function that I thought would do what I want: andrewFun <- function() { assign("obj1", 5, pos = sys.parent(n = 1)) assign("obj2", 6, pos = sys.parent(n = 1)) NULL } However, when I tried it, my results were the same as paulFun: assigned in the global environment, but not in the calling environment. Setting n = 0 seemed to limit the assignment to the interior of andrewFun: none of the printed obj values were affected. Help? andrewH -- View this message in context: http://r.789695.n4.nabble.com/reporting-multiple-objects-out-of-a-function-tp3873380p3876201.html Sent from the R help mailing list archive at Nabble.com.
On Wed, Oct 5, 2011 at 12:27 AM, andrewH <ahoerner at rprogress.org> wrote:> Dear folks, > > I?m trying to build a function to create and make available some variables I > frequently use for testing purposes. ?Suppose I have a function that takes > some inputs and creates (internally) several named objects. Say, > > fun1 <- function(x, y, z) {obj1 <- x; obj2 <- y; obj3 <- z > <missing stuff> > } > > Here is the challenge: After I run it, I want the objects to be available in > the calling environment, but not necessarily in the global environment. ?I > want them to be individually available, not as part of a list or some larger > object. ?I can not figure out how to do this. ?If I understand the situation > correctly, I am trying to move several separate objects from the environment > of the function to the environment in which the function was invoked (the > ?calling environment,? yes?). > > I?m pretty sure there is a command to do this, but I?m not sure how to find > it. Any help would be greatly appreciated ? either on the necessary code, or > on how to search for it, or a reference to a good discussion of this family > of problems.If the question is how to write things into the calling environment (also called the parent frame in R) then its like this: fun1 <- function(x, y, z, env = parent.frame()) { env$x <- x env$y <- y env$z <- z } fun1(1, 2, 3) x # 1 However, this seems very close to object oriented programming where fun1 is a method and x, y and z are properties and might represent a better organization of your program. For example, library(proto) p <- proto(fun1 = function(., x, y, z) { .$x <- x .$y <- y .$z <- z }) p$fun1(1, 2, 3) # set properties x, y, z p$x # 1 -- Statistics & Software Consulting GKX Group, GKX Associates Inc. tel: 1-877-GKX-GROUP email: ggrothendieck at gmail.com
On 10/05/2011 09:14 PM, andrewH wrote:> Thanks, Sina! This is very helpful and informative, but still not quite what > I want. > > So, here is the thing: When a function returns an object, that object is > available in the calling environment. If it is returned inside a function, > it is available in the function, but not outside of the function. What I > want to do is simply to return more than one object in the usual sense in > which functions return objects.Hi, As I understand it, you want to return multiple arguments without returning them explicitly as an object. This can probably be done, by I would advice against it because it makes your code harder to read. You dump something in the calling environment, and a new user (maybe yourself in a few months) has to do a lot of reasoning of what is happening under the hood, which object is dumped in which environment. I would just return a list. Alternatively, take a look at object oriented programming like Gabor suggested. This, however, still involves returning an object... Again, I would recommend doing this the standard R way.... cheers, Paul> Here is a test to see if a function fun does this, at least to the depth of > 1. > > obj1 <- 1 > obj2 <- 2 > > cat("obj1 in global=", obj1) > cat("obj2 in global=", obj2) > > wrapFun <- function(fun) { > obj1 <- 3 > obj2 <- 4 > cat("obj1 in calling=", obj1) > cat("obj2 in calling=", obj2) > fun() > cat("obj in calling=", obj) > cat("obj1 in calling=", obj1) > cat("obj2 in calling=", obj2) > } > > cat("obj1 in global=", obj1) > cat("obj2 in global=", obj2) > > > Suppose the function "fun" assigns the values 5 and 6 to obj1 and obj2. If > the function does what I want, this code should print: > obj1 in global= 1 > obj2 in global= 2 > obj1 in calling= 3 > obj2 in calling= 4 > obj1 in calling= 5 > obj2 in calling= 6 > obj1 in global= 1 > obj2 in global= 2 > > I turned Paul?s and Sina?s code into functions as follows: > paulFun <- function() { > obj1 <<- 5; > obj2 <<- 6; > } > > sinaFun <- function() { > attach(what = NULL, name = "my_env") > assign("obj1", 5, envir = as.environment("my_env")) > assign("obj1", 5, envir = as.environment("my_env")) > } > > Running these two functions in the code above yields: > > paulFun: > obj1 in global= 1 > obj2 in global= 2 > obj1 in calling= 3 > obj2 in calling= 4 > obj1 in calling= 3 > obj2 in calling= 4 > obj1 in global= 5 > obj2 in global= 6 > > So paulFun puts the objects in the global environment but not in the calling > environment. Let?s try sinaFun: > > sinaFun: > obj1 in global= 1 > obj2 in global= 2 > obj1 in calling= 3 > obj2 in calling= 4 > obj1 in calling= 3 > obj2 in calling= 4 > obj1 in global= 1 > obj2 in global= 2 > > sinaFun puts the objects in the new environment it defines, but they are > available in neither the calling nor the global environment. However, I was > immediately convinced that Sina had given me the tool I was missing: the > assign function. (Thanks, Sina!) But I was wrong (or used it wrong), and > now I am even more deeply confused. Here is a function that I thought would > do what I want: > > andrewFun <- function() { > assign("obj1", 5, pos = sys.parent(n = 1)) > assign("obj2", 6, pos = sys.parent(n = 1)) > NULL > } > > However, when I tried it, my results were the same as paulFun: assigned in > the global environment, but not in the calling environment. Setting n = 0 > seemed to limit the assignment to the interior of andrewFun: none of the > printed obj values were affected. > > Help? > > andrewH > > > -- > View this message in context: http://r.789695.n4.nabble.com/reporting-multiple-objects-out-of-a-function-tp3873380p3876201.html > Sent from the R help mailing list archive at Nabble.com. > > ______________________________________________ > R-help at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-help > PLEASE do read the posting guide http://www.R-project.org/posting-guide.html > and provide commented, minimal, self-contained, reproducible code.-- Paul Hiemstra, Ph.D. Global Climate Division Royal Netherlands Meteorological Institute (KNMI) Wilhelminalaan 10 | 3732 GK | De Bilt | Kamer B 3.39 P.O. Box 201 | 3730 AE | De Bilt tel: +31 30 2206 494 http://intamap.geo.uu.nl/~paul http://nl.linkedin.com/pub/paul-hiemstra/20/30b/770