Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Standard evaluation functions #79

Open
thomas-neitmann opened this issue May 21, 2020 · 11 comments
Open

Standard evaluation functions #79

thomas-neitmann opened this issue May 21, 2020 · 11 comments
Assignees
Labels
discussion enhancement New feature or request help wanted Extra attention is needed

Comments

@thomas-neitmann
Copy link
Owner

All functions currently use non-standard evaluation which is great for interactive use but IMO clumsy to program with. Having functions that accepts strings as arguments could come in very handy in {shiny} apps.

@thomas-neitmann thomas-neitmann added discussion enhancement New feature or request help wanted Extra attention is needed labels May 21, 2020
@thomas-neitmann thomas-neitmann self-assigned this May 21, 2020
@sjlva
Copy link
Contributor

sjlva commented Oct 11, 2020

Hi, Thomas,

Are you talking about making the kind of syntax below works?

line_chart(data = revenue_wide, x = "year", y = c("Roche", "Pfizer", "Novartis", "Bayer"))

If that is the case I can help.

@thomas-neitmann
Copy link
Owner Author

Yes, that's exactly what I had in mind. {dplyr} used to have functions that accept strings rather than symbols, i.e. mutate_() rather than mutate(). This is much easier to program with if you know that the inputs are strings.

@sjlva
Copy link
Contributor

sjlva commented Oct 11, 2020

Nice!

So, what do you think it is a better approach?
I read this about NSE and SE, and find out that Hadley Wickham suggests creating one function to SE and another to NSE like you said, so it would be functions like bar_chart() for NSE and bar_chart_() for SE.

But, it is also possible to make an auto evaluation function, like:

auto_evaluate <- function(x) {
  if(is.character(substitute(x))) {
    x <- dplyr::sym(x)
  } else {
    x <- rlang::enquo(x)
  }
  
  return(x)
}

Which would replace in {ggcharts} functions:

x <- rlang::enquo(x)
y <- rlang::enquo(y)
facet <- rlang::enquo(facet)

for

x <- auto_evaluate(x)
y <- auto_evaluate(y)
facet <- auto_evaluate(facet)

Which one do you prefer? Do you know another approaches?

I really would like to contribute, but sometimes I'm not very confident about my knowledge in R and good practices.

Thanks!

@thomas-neitmann
Copy link
Owner Author

I thought about something like the auto_evaluate function you proposed as well. However, I don't think it works. Imagine a datasets containing a variable called var and foo. What happens in the following scenario?

var <- "foo"
auto_evaluate(var)

var contains a string but is a symbol. I think this kind of ambiguity is the reason Hadley Wickham proposed to have to different functions: one with NSE and one with SE. Another approach is used quite frequently in base R: having a argument character.only that controls how the argument is evaluated. One good example is library:

pkg <- "dplyr"
library(pkg)
Error in library(pkg) : there is no package called ‘pkg’
library(pkg, character.only = TRUE)
Attaching package: ‘dplyr’

The following objects are masked from ‘package:stats’:

    filter, lag

The following objects are masked from ‘package:base’:

    intersect, setdiff, setequal, union

@thomas-neitmann
Copy link
Owner Author

@nathaneastwood How would you handle this?

@nathaneastwood
Copy link

So I actually use a function in {poorman} for this type of thing: https://github.com/nathaneastwood/poorman/blob/master/R/utils.R#L31
It works ok, but I wouldn't rely on it.

@nathaneastwood
Copy link

nathaneastwood commented Oct 12, 2020

By the way, is there no rlang solution to this? Since ggplot2 already imports rlang, I would be tempted to find a solution there, the dependency is already there.

@nathaneastwood
Copy link

By the way, have you considered the wrapr::let() function? It's fantastic.

@sjlva
Copy link
Contributor

sjlva commented Oct 17, 2020

By the way, is there no rlang solution to this? Since ggplot2 already imports rlang, I would be tempted to find a solution there, the dependency is already there.

Yes, there are some possible solutions in rlang. I was considering create some function to convert SE to NSE input but it sounds pretty unsafe.

What do you think about functions like page() and ls()? Both try to automatically determine whether you want standard or non-standard evaluation.

I thought about it a lot and I am very convinced that it would be better to have a function for NSE and another for SE.

@sjlva
Copy link
Contributor

sjlva commented Oct 17, 2020

Another approach is used quite frequently in base R: having a argument character.only that controls how the argument is evaluated. One good example is library:

I don’t think it’s a good idea to use an argument to change the behaviour of another argument because it makes function calls harder to understand. Don't you?

What do you think about having a function to SE and another to NSE? Make something like bar_plot() and bar_plot_() ?
I think it's the safer approach.

@thomas-neitmann
Copy link
Owner Author

I think having two separate functions, one with standard evaluation semantics and one with non-standard one is the way to go as it's completely transparent what is going on 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion enhancement New feature or request help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

3 participants