Clive Clive - 6 months ago 56
R Question

Optional arguments in S4 generics

is an S4 generic in RMongo. It is declared as

dbGetQuery(rmongo.object, collection, query, skip=0, limit=1000)

With a function like this in R,
are optional arguments. However, when I call it in this way

dbGetQuery(mongo, 'changesPerTypeEpoch', '{}', limit=10000)

I get an error:

Error in (function (classes, fdef, mtable) :

unable to find an inherited method for function ‘dbGetQuery’ for signature ‘"RMongo", "character", "character", "missing", "numeric"’

Looking at the source code, I found there are two signatures defined for the generic:

signature(rmongo.object="RMongo", collection="character", query="character", skip='numeric', limit='numeric')
signature(rmongo.object="RMongo", collection="character", query="character", skip='missing', limit='missing')

So in order to make it work without passing
, it needs to have another signature:

signature(rmongo.object="RMongo", collection="character", query="character", skip='missing', limit='numeric')

However, that makes me feel uncomfortable, because in order to make
optional arguments in a S4 generic, one has to define 2^n signatures. Is there any better way to define optional arguments in S4 generic?


A generic can limit the number of arguments on which dispatch actually occurs (using the 'signature' argument to setGeneric) (e.g., 'skip' and 'limit' will never be anything other than a numeric, so should not be included in dispatch. It's not unusual for optional arguments to appear after '...' (they need to be spelled in full, instead of being matched by position, but being explicit seems like a good idea here; '...' are needed to allow methods to expose their own additional arguments)

    function(x, y, ..., z=1, verbose=TRUE) standardGeneric("fancy"),
    signature=c("x", "y"))

One can also write methods for class 'ANY', although that's a pretty confident promise. Probably it would be better for RMongo to use the generics from the DBI package.