[Rd] New syntax for positional-only function parameters?
mikkmart
m|kkm@rt @end|ng |rom protonm@||@com
Thu Jan 11 01:29:58 CET 2024
Thanks Aidan and Ivan,
> Could you give a little more detail on this [...]? [...] Typically, the
> default scoping rules are sufficient to resolve these [...].
I agree these conflicts can be solved when spotted. And certainly more easily
so if there were a dedicated currying syntax in base R as Ivan mentioned.
However I think both users and package authors would benefit from being able
to prevent the collisions altogether.
To collect some data on the prevalence, I analyzed the 387 installed packages
on my machine, including 23 433 functions. Of those, 2 585 (11%) both accepted
... and had a "mangled" first argument name (one that did not start with a
lower case letter), indicating that the function might have benefited from
the availability of a positional-only parameter syntax.
> 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.
Thanks, Ivan, for the pointers. Following them I was able to put together a...
let's say proof of concept patch for this, included below. With the patch[1]
we indeed have for example:
g <- function(x, f, /, ...) match.call()
g(1, f, x = 2) == quote(g(1, f, x = 2))
Or:
my_lapply <- function(x, f, /, ...) {
res <- vector("list", length(x))
for (i in seq_along(x)) {
res[[i]] <- f(x[[i]], ...)
}
res
}
add <- function(x, y) x + y
my_lapply(1:5, add, x = 1)
Best wishes,
Mikko
[1]: Compiled with `RUN_BISON=1 make all recommended` on Windows, as it took
me a painful while to figure out.
Index: src/main/gram.y
===================================================================
--- src/main/gram.y (revision 85797)
+++ src/main/gram.y (working copy)
@@ -557,6 +557,7 @@
formlist: { $$ = xxnullformal(); }
| SYMBOL { $$ = xxfirstformal0($1); modif_token( &@1, SYMBOL_FORMALS ) ; }
| SYMBOL EQ_ASSIGN expr_or_help { $$ = xxfirstformal1($1,$3); modif_token( &@1, SYMBOL_FORMALS ) ; modif_token( &@2, EQ_FORMALS ) ; }
+ | formlist ',' '/' { $$ = xxaddformal0($1,$3, &@3); modif_token( &@3, SYMBOL_FORMALS ) ; }
| formlist ',' SYMBOL { $$ = xxaddformal0($1,$3, &@3); modif_token( &@3, SYMBOL_FORMALS ) ; }
| formlist ',' SYMBOL EQ_ASSIGN expr_or_help
{ $$ = xxaddformal1($1,$3,$5,&@3); modif_token( &@3, SYMBOL_FORMALS ) ; modif_token( &@4, EQ_FORMALS ) ;}
Index: src/main/match.c
===================================================================
--- src/main/match.c (revision 85797)
+++ src/main/match.c (working copy)
@@ -185,10 +185,13 @@
{
Rboolean seendots;
int i, arg_i = 0;
+ int nfargposonly = 0;
SEXP f, a, b, dots, actuals;
actuals = R_NilValue;
for (f = formals ; f != R_NilValue ; f = CDR(f), arg_i++) {
+ /* Get count of positional-only formal arguments */
+ if (TAG(f) == Rf_install("/")) nfargposonly = arg_i + 1;
/* CONS_NR is used since argument lists created here are only
used internally and so should not increment reference
counts */
@@ -218,6 +221,7 @@
a = actuals;
arg_i = 0;
while (f != R_NilValue) {
+ if (arg_i >= nfargposonly) {
SEXP ftag = TAG(f);
const char *ftag_name = CHAR(PRINTNAME(ftag));
if (ftag != R_DotsSymbol && ftag != R_NilValue) {
@@ -241,6 +245,7 @@
}
}
}
+ }
}
f = CDR(f);
a = CDR(a);
@@ -257,7 +262,7 @@
a = actuals;
arg_i = 0;
while (f != R_NilValue) {
- if (fargused[arg_i] == 0) {
+ if (fargused[arg_i] == 0 && arg_i >= nfargposonly) {
if (TAG(f) == R_DotsSymbol && !seendots) {
/* Record where ... value goes */
dots = a;
@@ -310,6 +315,10 @@
seendots = TRUE;
f = CDR(f);
a = CDR(a);
+ } else if (TAG(f) == Rf_install("/")) {
+ /* Ignore positional-only marker */
+ f = CDR(f);
+ a = CDR(a);
} else if (CAR(a) != R_MissingArg) {
/* Already matched by tag */
/* skip to next formal */
Index: src/main/unique.c
===================================================================
--- src/main/unique.c (revision 85797)
+++ src/main/unique.c (working copy)
@@ -1919,10 +1919,14 @@
/* Attach the argument names as tags */
- for (f = formals, b = rlist; b != R_NilValue; b = CDR(b), f = CDR(f)) {
- SET_TAG(b, TAG(f));
+ int nfargposonly = 0, arg_i = 0;
+ for (f = formals ; f != R_NilValue ; f = CDR(f), arg_i++) {
+ if (TAG(f) == Rf_install("/")) nfargposonly = arg_i + 1;
}
+ for (f = formals, b = rlist, arg_i = 0; b != R_NilValue; b = CDR(b), f = CDR(f), arg_i++) {
+ if (arg_i >= nfargposonly) SET_TAG(b, TAG(f));
+ }
/* Handle the dots */
More information about the R-devel
mailing list