From osklyar at maninvestments.com  Tue May 13 12:54:10 2008
From: osklyar at maninvestments.com (Sklyar, Oleg (MI London))
Date: Tue, 13 May 2008 11:54:10 +0100
Subject: [Rd] 'cat' and 'write' as generic, just like 'c', 'cbind' etc?
Message-ID: <1A68FCB28DE72F4BA3B967E6506CCE43022948DA@mildnpexmb01.maninvestments.ad.man.com>

Dear list:

is there any good reason why 'c', 'cbind', 'rbind' etc (all defined as
'function(..., <rest>)') are generic and thus methods can be defined
whereas such quite useful functions like 'cat' and 'write' are not? 

Would it not be reasonable to add such functionality? This would allow
to define S3/S4 methods for cat and write for complex objects defining
the way they should be output to files and std out.

As a use case, I am working with ASCII files formatted in a particular
way, when they are read, corresponding objects are created that
replicate their structure and thus it seems reasonable to recreate the
same ASCII structure when one does cat or write (which calls cat) on
those objects. The default print/show would actually in this case have
different, more compact output.

I might be doing something wrong about defining 'cat' as a method, but
its help page indeed does not mention anything about being generic,
whereas those of 'c', 'cbind' etc do. So the question is rather: could
it be made generic?

Thanks for responces,
Oleg

The following example shows the way 'c' can be redefined, while 'cat'
cannot although they are redefined following exactly the same
methodology:

## R 2.7.0 (2008-04-22) Linux 2.6.9-42, x86_64

setClass("MyClass", representation("numeric", comment="character"))

setGeneric("c")
setMethod("c", "MyClass",
    function(x, ..., recursive=FALSE) {
        print("CALLED: c S4 method")
        args = list(x,...)
        if (!all(sapply(args, inherits, "MyClass")))
            stop("all arguments must be of class MyClass")
        data = lapply(args, function(x) x at .Data)
        comm = lapply(args, function(x) x at comment)
        new("MyClass", do.call("c", data), comment=do.call("c", comm))
    }
)

a = new("MyClass", runif(3), comment=c("a","b","c"))
b = new("MyClass", -runif(3), comment=c("d","e","f"))
c(a,b)

## does not work in S4
setGeneric("cat")
setMethod("cat", "MyClass",
    function(x, ..., file = "", sep = " ", fill = FALSE, labels = NULL,
        append = FALSE) {
        print("CALLED: cat S4 method")
        cat("Data:", x at .Data,"\n", file=file, append=append)
        cat("Comment:", x at comment, "\n", file=file, append=append)
        invisible(NULL)
    }
)
## omitting x following the function definition does not solve the
problem

cat(a,"\n")
cat(b,"\n")

## does not work in S3
cat.MyClass = function(..., file = "", sep = " ", fill = FALSE, labels =
NULL,
    append = FALSE) {
    print("CALLED: cat.MyClass")
    x = c(...)
    cat("Data:", x at .Data,"\n", file=file, append=append)
    cat("Comment:", x at comment, "\n", file=file, append=append)
    invisible(NULL)
}

cat(a,"\n")



Dr Oleg Sklyar
Technology Group
Man Investments Ltd
+44 (0)20 7144 3803
osklyar at maninvestments.com


**********************************************************************
The contents of this email are for the named addressee(s...{{dropped:22}}



[Rd] 'cat' and 'write' as generic, just like 'c', 'cbind' etc?
Sklyar, Oleg (MI London