Henrik Bengtsson
2025-Dec-11 06:40 UTC
[Rd] rep(): Expecting an argument-is-missing error, but ...
What's going on here: $ R --vanilla --quiet> f <- function(n) rep("x", times = n) > f()[1] "x" ?> getRversion()[1] ?4.5.2? /Henrik
Rui Barradas
2025-Dec-11 07:40 UTC
[Rd] rep(): Expecting an argument-is-missing error, but ...
?s 06:40 de 11/12/2025, Henrik Bengtsson escreveu:> What's going on here: > > $ R --vanilla --quiet >> f <- function(n) rep("x", times = n) >> f() > [1] "x" > > ? > >> getRversion() > [1] ?4.5.2? > > /Henrik > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-develHello, I can reproduce this on Windows. Microsoft Windows [Version 10.0.22631.5039] (c) Microsoft Corporation. Todos os direitos reservados. C:\>R --vanilla --quiet > f <- function(n) rep("x", times = n) > f function(n) rep("x", times = n) > f() [1] "x" > getRversion() [1] '4.5.2' > g <- function(n) rep(1, times = n) > g function(n) rep(1, times = n) > g() [1] 1 > h <- function(n) rep(1, n) > h function(n) rep(1, n) > h() [1] 1 > i <- function(n) rep(1, each = n) > i() [1] 1 > sessionInfo() R version 4.5.2 (2025-10-31 ucrt) Platform: x86_64-w64-mingw32/x64 Running under: Windows 11 x64 (build 22631) Matrix products: default LAPACK version 3.12.1 locale: [1] LC_COLLATE=Portuguese_Portugal.utf8 LC_CTYPE=Portuguese_Portugal.utf8 [3] LC_MONETARY=Portuguese_Portugal.utf8 LC_NUMERIC=C [5] LC_TIME=Portuguese_Portugal.utf8 time zone: Europe/Lisbon tzcode source: internal attached base packages: [1] stats graphics grDevices utils datasets methods base loaded via a namespace (and not attached): [1] compiler_4.5.2 tools_4.5.2 > q() Hope this helps, Rui Barradas
Peter Langfelder
2025-Dec-11 08:21 UTC
[Rd] rep(): Expecting an argument-is-missing error, but ...
I think it's a bit of a quirk of rep:> rep("x") > [1] "x"Help of 'rep' does state this: The default behaviour is as if the call was rep(x, times = 1, length.out = NA, each = 1) So it seems to even be documented. Peter Peter On Thu, Dec 11, 2025 at 2:40?PM Henrik Bengtsson <henrik.bengtsson at gmail.com> wrote:> > What's going on here: > > $ R --vanilla --quiet > > f <- function(n) rep("x", times = n) > > f() > [1] "x" > > ? > > > getRversion() > [1] ?4.5.2? > > /Henrik > > ______________________________________________ > R-devel at r-project.org mailing list > https://stat.ethz.ch/mailman/listinfo/r-devel
Ivan Krylov
2026-Feb-15 07:30 UTC
[Rd] rep(): Expecting an argument-is-missing error, but ...
? Wed, 10 Dec 2025 22:40:29 -0800 Henrik Bengtsson <henrik.bengtsson at gmail.com> ?????:> What's going on here: > > $ R --vanilla --quiet > > f <- function(n) rep("x", times = n) > > f() > [1] "x"Let's take these R functions: not_rep <- compiler::cmpfun(\(x, times = 1) invisible(times)) wrap_not_rep <- compiler::cmpfun(\(times) not_rep(1, times = times)) In a call from wrap_not_rep() to not_rep(1, times = times), the thing being matched against the formals is a promise to evaluate 'times' in the wrap_not_rep()'s environment, so Rf_matchArgs_NR matches it successfully and not_rep() eventually forces the promise and signals an argument-is-missing exception. What about the following function? wrap_rep <- compiler::cmpfun(\(times) rep(1, times = times)) Being a pritmitive, rep() performs its own argument matching, so in a call from wrap_rep() to rep(1, times = times), things happen differently. First, it receives the "raw" arguments, without them being wrapped into promises: (gdb) call R_inspect(args) @5555585b2220 02 LISTSXP g1c0 [MARK,REF(2)] @5555585a5700 14 REALSXP g1c1 [MARK,REF(65535)] (len=1, tl=0) 1 TAG: @555557d17458 01 SYMSXP g1c0 [MARK,REF(65535)] "times" @555557d17458 01 SYMSXP g1c0 [MARK,REF(65535)] "times" Then it calls DispatchOrEval(), which evaluates the expressions in the call, replacing the "times" symbol with R_MissingArg. Only then it calls Rf_matchArgs_NR: (gdb) call R_inspect(supplied) @5555588f74a8 02 LISTSXP g0c0 [STP] @5555585a5700 14 REALSXP g0c1 [REF(65535)] (len=1, tl=0) 1 TAG: @555557d17458 01 SYMSXP g0c0 [REF(65535)] "times" @5555559c6320 01 SYMSXP g0c0 [MARK,REF(7008)] [missing argument] Rf_matchArgs_NR then faithfully substitutes that missing argument into the return value together with other missing arguments that it substitutes for every value that wasn't passed at all: (gdb) call R_inspect(args) @5555588fc850 02 LISTSXP g0c0 [STP] @5555585a5700 14 REALSXP g0c1 [REF(65535)] (len=1, tl=0) 1 # this one was passed as missing @5555559c6320 01 SYMSXP g0c0 [MARK,REF(7010)] [missing argument] # the following ones weren't passed at all @5555559c6320 01 SYMSXP g0c0 [MARK,REF(7010)] [missing argument] @5555559c6320 01 SYMSXP g0c0 [MARK,REF(7010)] [missing argument] @5555559c6320 01 SYMSXP g0c0 [MARK,REF(7010)] [missing argument] There doesn't seem to be a way to distinguish between the two kinds of missing arguments in the return value. In order to cause an argument-is-missing error, rep() would have to walk the list of supplied arguments before matching them, replacing the R_MissingArg with something else, then match the arguments, then complain about the missing argument replacement being matched to a non-dots formal argument. "To call this an ugly hack would be to insult all existing ugly hacks at large in the world." Is there a better way? -- Best regards, Ivan