From ripley at stats.ox.ac.uk  Thu Mar 19 11:34:03 2009
From: ripley at stats.ox.ac.uk (Prof Brian Ripley)
Date: Thu, 19 Mar 2009 10:34:03 +0000 (GMT)
Subject: [Rd] sprintf("%d", integer(0)) aborts
In-Reply-To: <77EB52C6DD32BA4D87471DCD70C8D700DF1A0E@NA-PA-VBE03.na.tibco.com>
References: <77EB52C6DD32BA4D87471DCD70C8D700DF1A0E@NA-PA-VBE03.na.tibco.com>
Message-ID: <alpine.LFD.2.00.0903191024300.12166@gannet.stats.ox.ac.uk>

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,                  ripley at 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



[Rd] sprintf("%d", integer(0)) aborts
Prof Brian Ripley