[Rd] two small wishes (with code sugegstions) for R-core

Jens Oehlschlägel joehl at web.de
Mon Nov 2 14:15:03 CET 2009


Dear R developers,

It would be great if you could implement the two minor code changes suggested below, which would help processing large objects in R.


Jens Oehlschlägel


# Wish no. 1: let [.AsIs return the class AFTER subsetting, not the class of the original object
# Wish no. 2: adjust write.csv and write.csv2 for multiple calls in chunked writing

# Rationale no. 1: a couple of packages will return a different class than SomeClass when subsetting with [.SomeClass 
# and still need to keep the AsIs property
# Examples for classes returning different classes on subscipting are in packages 'bit', 'ff', 'bigmemory'
# For classes where [.SomeClass will return class SomeClass, such a change will not hurt

# Code suggestion no. 1: please use 
"[.AsIs" <- function (x, i, ...){
      ret <- NextMethod("[")
      oldClass(ret) <- c("AsIs", oldClass(ret))
      ret
}
# instead of
"[.AsIs" <- function (x, i, ...)
structure(NextMethod("["), class = class(x))


# Rationale no. 2: write.csv and write.csv2 currently enforce that a header must be written, even with append=TRUE
# This prevents a csv file being written in chunks.
# If argument append=TRUE is used, a header should not be enforced (may be even be forbidden)

# Code suggestion no. 2: please use
write.csv <-
function (...)
{
    Call <- match.call(write.table, expand.dots = TRUE)
    for (argname in c("col.names", "sep", "dec", "qmethod")) if (!is.null(Call[[argname]]))
        warning(gettextf("attempt to set '%s' ignored", argname),
            domain = NA)
    rn <- eval.parent(Call$row.names)
    ap <- eval.parent(Call$append)
    Call$col.names <- if (is.logical(ap) && ap) FALSE else {if (is.logical(rn) && !rn) TRUE else NA}
    Call$sep <- ","
    Call$dec <- "."
    Call$qmethod <- "double"
    Call[[1L]] <- as.name("write.table")
    eval.parent(Call)
}
write.csv2 <-
function (...)
{
    Call <- match.call(write.table, expand.dots = TRUE)
    for (argname in c("col.names", "sep", "dec", "qmethod")) if (!is.null(Call[[argname]]))
        warning(gettextf("attempt to set '%s' ignored", argname),
            domain = NA)
    rn <- eval.parent(Call$row.names)
    ap <- eval.parent(Call$append)
    Call$col.names <- if (is.logical(ap) && ap) FALSE else {if (is.logical(rn) && !rn) TRUE else NA}
    Call$sep <- ";"
    Call$dec <- ","
    Call$qmethod <- "double"
    Call[[1L]] <- as.name("write.table")
    eval.parent(Call)
}
# instead of
write.csv <- function (...) 
{
    Call <- match.call(expand.dots = TRUE)
    for (argname in c("col.names", "sep", "dec", "qmethod")) if (!is.null(Call[[argname]])) 
        warning(gettextf("attempt to set '%s' ignored", argname), 
            domain = NA)
    rn <- eval.parent(Call$row.names)
    Call$col.names <- if (is.logical(rn) && !rn) 
        TRUE
    else NA
    Call$sep <- ","
    Call$dec <- "."
    Call$qmethod <- "double"
    Call[[1L]] <- as.name("write.table")
    eval.parent(Call)
}
write.csv2 <- 
function (...) 
{
    Call <- match.call(expand.dots = TRUE)
    for (argname in c("col.names", "sep", "dec", "qmethod")) if (!is.null(Call[[argname]])) 
        warning(gettextf("attempt to set '%s' ignored", argname), 
            domain = NA)
    rn <- eval.parent(Call$row.names)
    Call$col.names <- if (is.logical(rn) && !rn) 
        TRUE
    else NA
    Call$sep <- ";"
    Call$dec <- ","
    Call$qmethod <- "double"
    Call[[1L]] <- as.name("write.table")
    eval.parent(Call)
}



More information about the R-devel mailing list