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 */ ______________________________________________ R-devel@r-project.org mailing list https://stat.ethz.ch/mailman/listinfo/r-devel