Dear List, I'm writing to gauge interest in new syntax for positional-only function parameters to be added to R. The pattern of functions accepting other functions as inputs and passing additional ... arguments to them is prevalent throughout the R ecosystem. Currently, however, all such functions must one way or another tackle the problem of inadvertently passing arguments meant to go to ... as arguments to the function itself instead. The typical workaround is to use somehow obfuscated names for the parameters in the main function in order to make such collisions unlikely. For example lapply() and friends with signatures like: function (X, FUN, ...) In practice this pattern avoids many collisions, but it cannot guarantee that they won't happen. It would seem to me preferrable to avoid the root cause of the issue altogether by having the language feature of declaring function parameters as positional-only. Python's PEP 570 discusses the same issue in the context of Python [1]. Concretely, borrowing syntax from Python, the proposal would be to have something along the lines of: g <- function(x, f, /, ...) match.call() g(1, f, x = 2) == quote(g(1, f, x = 2)) Rather than the current situation of: g <- function(x, f, ...) match.call() g(1, f, x = 2) == quote(g(x = 2, f = 1, f)) Given the prevalence of the issue, is this something that you would see as worth pursuing for R? Best regards, Mikko [1]: https://peps.python.org/pep-0570/
Lakshman, Aidan H
2023-Nov-09 14:31 UTC
[Rd] New syntax for positional-only function parameters?
Hi Mikko,> Given the prevalence of the issue, is this something that you would see as worth pursuing for R?Could you give a little more detail on this, potentially with an example of the collisions you?re referring to (and maybe an example that throws an error and/or does something unexpected)? I can?t think of a time I?ve had an issue that would have been solved/helped with positional-only parameters, though it could just be a use-case outside of my normal work. Typically, the default scoping rules are sufficient to resolve these in a way that feels (to me at least) pretty intuitive.> The typical workaround is to use somehow obfuscated names for the parameters in the main function in order to make such collisions unlikely?In practice this pattern avoids many collisions, but it cannot guarantee that they won't happen.This is a fair point and the PEP you linked is a great writeup, but it?s worth mentioning that the development paradigms of Python and R aren?t exactly the same. My gut feeling is that this change would take a significant amount of work to solve a somewhat edge case. Anything involving changes to the argument parser has a nontrivial chance of inadvertently affecting other pieces of R, and with R?s focus on stability and backwards-compatibility they typically try to avoid big changes to the core core functionality. I am not R-core, but I?d be doubtful that it would be a high priority project for the core members for those reasons. Again, if there were examples of packages/code that would be simplified by this then that could change things, although I doubt that any changes would be made to functions like the `*apply` family due to backwards-compatibility issues. That said, it?s an interesting idea. If you have an implementation that adds this capability, I?d be interested in taking a look. From a quick look at the internals, I?m expecting you?d need to make a few changes to `src/main/builtin.c` and possibly `src/main/eval.c`. I?m far from an expert on this, so I?d also be interested in anyone else?s input. -Aidan ----------------------- Aidan Lakshman (he/him)<https://www.ahl27.com/> Doctoral Fellow, Wright Lab<https://www.wrightlabscience.com/> University of Pittsburgh School of Medicine Department of Biomedical Informatics ahl27 at pitt.edu (724) 612-9940 From: R-devel <r-devel-bounces at r-project.org> on behalf of mikkmart via R-devel <r-devel at r-project.org> Date: Monday, November 6, 2023 at 17:41 To: r-devel at r-project.org <r-devel at r-project.org> Subject: [Rd] New syntax for positional-only function parameters? Dear List, I'm writing to gauge interest in new syntax for positional-only function parameters to be added to R. The pattern of functions accepting other functions as inputs and passing additional ... arguments to them is prevalent throughout the R ecosystem. Currently, however, all such functions must one way or another tackle the problem of inadvertently passing arguments meant to go to ... as arguments to the function itself instead. The typical workaround is to use somehow obfuscated names for the parameters in the main function in order to make such collisions unlikely. For example lapply() and friends with signatures like: function (X, FUN, ...) In practice this pattern avoids many collisions, but it cannot guarantee that they won't happen. It would seem to me preferrable to avoid the root cause of the issue altogether by having the language feature of declaring function parameters as positional-only. Python's PEP 570 discusses the same issue in the context of Python [1]. Concretely, borrowing syntax from Python, the proposal would be to have something along the lines of: g <- function(x, f, /, ...) match.call() g(1, f, x = 2) == quote(g(1, f, x = 2)) Rather than the current situation of: g <- function(x, f, ...) match.call() g(1, f, x = 2) == quote(g(x = 2, f = 1, f)) Given the prevalence of the issue, is this something that you would see as worth pursuing for R? Best regards, Mikko [1]: https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpeps.python.org%2Fpep-0570%2F&data=05%7C01%7Cahl27%40pitt.edu%7C14977c4a084b4005d90508dbdf197ca3%7C9ef9f489e0a04eeb87cc3a526112fd0d%7C1%7C0%7C638349072804739356%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=0RtGGMmsrx9YTC23ZHD2qLRUXvb%2Fd9JqBWvn1VYaul8%3D&reserved=0<https://peps.python.org/pep-0570/> ______________________________________________ R-devel at r-project.org mailing list https://nam12.safelinks.protection.outlook.com/?url=https%3A%2F%2Fstat.ethz.ch%2Fmailman%2Flistinfo%2Fr-devel&data=05%7C01%7Cahl27%40pitt.edu%7C14977c4a084b4005d90508dbdf197ca3%7C9ef9f489e0a04eeb87cc3a526112fd0d%7C1%7C0%7C638349072804739356%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C&sdata=18L686XGln2pUwUIjIFvaqyn8BgoC2uS%2Fw2ZMkTBUCc%3D&reserved=0<https://stat.ethz.ch/mailman/listinfo/r-devel> [[alternative HTML version deleted]]
Ivan Krylov
2023-Nov-11 05:28 UTC
[Rd] New syntax for positional-only function parameters?
6 ?????? 2023 ?. 22:54:24 GMT+03:00, mikkmart via R-devel <r-devel at r-project.org> ?????:>The pattern of functions accepting other functions as inputs and >passing additional ... arguments to them is prevalent throughout >the R ecosystem. Currently, however, all such functions must one >way or another tackle the problem of inadvertently passing arguments >meant to go to ... as arguments to the function itself instead. > >The typical workaround is to use somehow obfuscated names for the >parameters in the main function in order to make such collisions >unlikely.Some additional workarounds can be suggested. For example, * Take a MoreArgs argument, like in mapply(). Cons: this argument forwarding is not perfect, e.g. a missing argument will cause an error, even if the target function could have handled it. * Curry some or all of the arguments, i.e. replace the original closure with the one calling the original function and passing it extra arguments, e.g. my_lapply(X, curry(f, X = X, f = f), ...). I think I remember someone asking for dedicated currying syntax in R. Cons: a simple curry() implementation will suffer from the same problem. * Instead of taking the extra arguments in the same call, return a closure that would take them and perform the call: e.g. my_lapply(f, X)(...). Cons: this is not what R code usually looks like.>Python's PEP 570 discusses the same issue in the context of Python [1]. > >Concretely, borrowing syntax from Python, the proposal would be >to have something along the lines of: > > g <- function(x, f, /, ...) match.call() > g(1, f, x = 2) == quote(g(1, f, x = 2))This is realistic to implement. In addition to changes in gram.y (or, perhaps, to the declare() special interface for giving extra instructions to the parser that was suggested for declaring arguments for NSE) to mark the formals as positional-only, the argument matching mechanism in src/main/match.c:matchArgs_NR will need to be changed to take the flag into account. I think it's also possible to implement a function with its own argument matching in C by making it .External and walking the LISTSXP it receives, but that's of course much less convenient that writing R. Unfortunately, this won't immediately help the original lapply(). Somewhere, there's a lot of R code calling lapply(X = X, FUN = FUN, ...), which is currently valid. If positional-only arguments are adopted, lapply() would have to go through a long deprecation cycle before being able to protect its callers from argument name collisions. Still, a new lapply2() would be able to use this immediately. -- Best regards, Ivan