On Wed, 18 Mar 2009, William Dunlap wrote:

In R's sprintf() if any of the arguments has length 0
the function aborts.  E.g.,

  > sprintf("%d", integer(0))
  Error in sprintf("%d", integer(0)) : zero-length argument
  > sprintf(character(), integer(0))
  Error in sprintf(character(), integer(0)) :
    'fmt' is not a non-empty character vector

This comes up in code like
  x[nchar(x)==0] <- sprintf("No. %d", seq_along(x)[nchar(x)==0])
which works if x contains any empty strings
  x<-c("One","Two","") # changes "" -> "No. 3"
but not if it doesn't
  x<-c("One","Two","Three") # throws error instead of doing nothing

When I wrote S+'s sprintf() I had it act like the binary
arithmetic operators, returning a zero long result if any
argument were zero long.  (Otherwise its result is as long
as the longest input.)  I think it would be nice if R's
sprintf did this also.

Currently you must add defensive code (if (any(nchar(x)==0))...)
to make functions using sprintf to work in all cases and that
muddies up the code and slows things down.

Do you think this is a reasonable thing to do?  I've attached
a possible patch to src/main/sprintf.c makes the examples above
return character(0).

Yes. It was deliberate that it works (and is documented) the way it is, and I've not previously seen any problematic examples. But at least for the ... args, allowing zero-length arguments seems very reasonable. I'm less convinced by zero-length formats, but the rule may be easier to explain if we allow them.

This will need a documentation change, and I'll look into it when I can.


Bill Dunlap
TIBCO Software Inc - Spotfire Division
wdunlap tibco.com

-------------------------------------------------------------------

Index: sprintf.c
===================================================================
--- sprintf.c   (revision 48148)
+++ sprintf.c   (working copy)
@@ -79,13 +79,13 @@
    static R_StringBuffer outbuff = {NULL, 0, MAXELTSIZE};
    Rboolean use_UTF8;

-    outputString = R_AllocStringBuffer(0, &outbuff);
-
    /* grab the format string */
    nargs = length(args);
    format = CAR(args);
-    if (!isString(format) || length(format) == 0)
+    if (!isString(format))
       error(_("'fmt' is not a non-empty character vector"));
+    if (length(format) == 0)
+       return allocVector(STRSXP, 0) ;
    args = CDR(args); nargs--;
    if(nargs >= 100)
       error(_("only 100 arguments are allowed"));
@@ -97,9 +97,12 @@
    for(i = 0; i < nargs; i++) {
       lens[i] = length(a[i]);
       if(lens[i] == 0)
-           error(_("zero-length argument"));
+           return allocVector(STRSXP, 0) ;
       if(maxlen < lens[i]) maxlen = lens[i];
    }
+
+    outputString = R_AllocStringBuffer(0, &outbuff);
+
    if(maxlen % length(format))
       error(_("arguments cannot be recycled to the same length"));
    for(i = 0; i < nargs; i++)


--
Brian D. Ripley,                  rip...@stats.ox.ac.uk
Professor of Applied Statistics,  http://www.stats.ox.ac.uk/~ripley/
University of Oxford,             Tel:  +44 1865 272861 (self)
1 South Parks Road,                     +44 1865 272866 (PA)
Oxford OX1 3TG, UK                Fax:  +44 1865 272595

______________________________________________
R-devel@r-project.org mailing list
https://stat.ethz.ch/mailman/listinfo/r-devel

Reply via email to