Cannot get the value of an object with rlang

My goal is to run a function that will use an object created into another function.

I do have a function that initialize an object and run another function after that.
I do not achieve to retrieve the value of the object and I don't understand why.

Here's a quick example:

library(tidyverse)

func_1 <- function() {
  ToFilter <- c("group")
  func_2()
}

func_2 <- function() {
  selection <-
    PlantGrowth %>%
    dplyr::filter(sym(ToFilter) == "trt2")
}

test <- func_1()

I do get the following error:

> test <- func_1()
Error in `dplyr::filter()`:
! Problem while computing `..1 = ... == "trt2"`.
Caused by error in `noquote()`:
! object 'ToFilter' not found

What I need to get is that:

selection <-
  PlantGrowth %>%
  dplyr::filter(group == "trt2")

I tried a lot of different things with no success. I don't understand because sym(ToFIlter) gives group as a result, which is exactly what I need. noquote() and ensym() are also working externally to a function, but not into it.

ToSel <- c("group")
ToSel
sym(ToSel)
noquote(ToSel)
ensym(ToSel)
> ToSel <- c("group")
> ToSel
[1] "group"
> sym(ToSel)
group
> noquote(ToSel)
[1] group
> ensym(ToSel)
group
>

I don't understand how to get the result I want, and I'm pretty lost in the rlang world. Could you help me? Thanks a lot!

I dont see that this relates to rlang , or if so its only indirectly. They key would seem to be appreciating R's rules of scoping. The functions are not simply macros; they have associated environments.

A clean code approach would be to be explicit about passing arguments into your functions, and not to attempt to rely on objects being present in the calling environments , for lack of a better word, incidentally.

In general the best advice i can give you as is to pass everything the function should see in order to do its work as argument(s) into it, and only deviate from this when you have greater experience with coding in R.

Thank you very much for your answer and advices.

The rational behind my initial code is to compute several programs a lot of times (each) with different parameters, without having to go back inside each single program (over an hundred sometimes). If I need to modify or add another output (for example, another subgroup analysis). Each of my program would be wrapped in a func_2() function.

I took a quick and easy example with PlantGrowth (maybe not the best to explain my context).

After further investigations I think I found something that is working, by mentionning the parameters names in func_2().

Context of the example:
PlantGrowth contains records associated to group = ctrl, trt1 or trt2.

I want to export as much .csv file as defined in func_1(). In this example, I want to get one file for group = trt1, one for group = trt2. If, another day, I want to also get a file for group = ctrl or delete trt1 from my exports, I need to be able to do it quickly in func_1().

I would like to avoid having a a lot of func_2() calls inside each programs I will run (once again, sometimes more than 100).

Here's the code. I put all the functions in the same chunk but actually in my project those are separated (one program for func_1, and several different programs doing different things wrapped in a func_2 function wich will be run as much as I can depending of the subgroups I need to work on).

I'm sure it can be optimized, but it's currently working.

library(tidyverse)

func_1 <- function() {
  ToFilter  <- c("group")              # Column to filter on
  FilterVal <- c("trt2")               # Value to get from filter
  expname  <- c("group2")              # Extension to final exported file
  func_2(ToFilter, FilterVal, expname) # Call func_2()
  
  ToFilter  <- c("group")
  FilterVal <- c("trt1") 
  expname  <- c("group1")
  func_2(ToFilter, FilterVal, expname)
}

func_2 <- function(ToFilter, FilterVal, expname) {
  FileSel <-
    PlantGrowth %>%
    dplyr::filter(!!sym(ToFilter) == FilterVal)
  
  ToExp <- paste0("table_", expname, ".csv")
  
  write_csv(FileSel, ToExp)
}

func_1()

This topic was automatically closed 21 days after the last reply. New replies are no longer allowed.

If you have a query related to it or one of the replies, start a new topic and refer back with a link.