setGeneric for a list of objects - r

I have the following function:
myFunction = function(objects,params) {
for (i in 1:length(objects)) {
object = objects[[i]]
object = myOtherFunction(objects, params)
objects[[i]] = object
}
return (objects)
}
#' #rdname myFunction
#' #aliases myFunction
setMethod("myFunction", signature(object ="list"), myFunction)
How can I properly set the setMethod() and setGeneric() methods to accept a list of objects of a given type, let's say a list of objects of type SingleCellExperiment ?

If you want to write different methods to handle lists of class foo and lists of class bar then S4 will need some help, since both objects are of class list and hence the same method will be called in both cases.
There are a few options:
firstly, do you need to use lists at all? Don't forget all the base types in R are vectors, so for simple classes like
setClass("cuboid",slots=list(
height="numeric",
width="numeric",
depth="numeric"
)) -> cuboid
if you want to represent a set of multiple cuboids you don't need to use a list at all, just feed vectors of values to cuboid. This doesn't work as well for more exotic classes, though.
alternatively, you can write a list method with some extra logic to determine which lower-order method to dispatch. You should also think about what to do if the list contains objects of multiple different classes.
in some situations you might be able to use either lapply or a function that takes arbitrary numbers of arguments via .... In the latter case you may be able to make use of dotsMethods (check the help page on that topic for more info).
If you want to write a method that will only be called on lists of objects of class foo and there may exist another method that wants to operate on lists, then you can either:
write a method for class foo directly, and then use sapply or lapply rather than calling your function on the list
write a method for class list that checks whether the list has foos in it and if it doesn't, calls nextMethod.

Related

What is the difference between new() and setClass() in R?

I am curious as to what the functional difference is between between new() and setClass() in R?
I answered another question that seems to suggest that they operate identically, except that new() is potentially far less "restrictive."
You can refer to this link in the description on top of the page and the Value section:
r documentation setClass
From the link:
A generator function suitable for creating objects from the class is
returned, invisibly. A call to this function generates a call to new
for the class. The call takes any number of arguments, which will be
passed on to the initialize method. If no initialize method is defined
for the class or one of its superclasses, the default method expects
named arguments with the name of one of the slots and unnamed
arguments that are objects from one of the contained classes.
Typically the generator function is assigned the name of the class,
for programming clarity. This is not a requirement and objects from
the class can also be generated directly from new. The advantages of
the generator function are a slightly simpler and clearer call, and
that the call will contain the package name of the class (eliminating
any ambiguity if two classes from different packages have the same
name).
If the class is virtual, an attempt to generate an object from either
the generator or new() will result in an error.
The two functions have completely different side effects. You need to call setClass when you are defining a class. You can't just do
new("square",x=0,y=0,side=1) -> mySquare
and expect R to know what a square is (you will get an error along the lines of "undefined class 'square'"). If you do
setClass("square",
slots=c(
x="numeric",
y="numeric",
side="numeric"
)
) -> square
mySquare <- square(x=0,y=0,side=1)
then you have defined the class square and can then call the function square to create objects from it. You can also at this point call new("square",...) as well but the effect is the same.
If you want to create a constructor function that doesn't just take slot names as arguments, then the recommended approach is to create an ordinary function along the lines of
createSquare <- function(r,theta,side){
square(x=r*cos(theta),y=r*sin(theta),side=side)
}

subclass of `list` using S3 classes in R?

I'd like to make a subclass of list. As in the answer to this question, I'll need to define a custom method for [.
What other methods do I need to make so that my list subclass does not lose its subclass when users manipulate it? Filter, I think.
This gets me a few more functions that operate on lists:
> methods(class = "list")
[1] all.equal as.data.frame coerce escape Ops relist select within
But I don't think any of those return new lists that should have the same type as the old one.
Which am I missing?

Add extra arguments to implicit S4 generic for a primitive function

Take the function names: that's a primitve function in R. For primitive functions, an implicit S4 generic is created, so it is possible to construct S4 methods for that function.
Take an S4 class defined as follows :
setClass("aClass",
representation=list(
values = "character",
id = "numeric"
),
prototype=list(
values = character(0),
id = numeric(0)),
validity=function(object){
length(object#values)==length(object#id)
}
)
Now I want to create a function to extract the names, either sorted or unsorted. I wanted to do this using the function names to avoid having to make a new function getNames() or whatever, as that's less intuitive.
The following gives an idea of what needs to be done:
setMethod("names",signature="aClass",
function(x,ordered=TRUE){
if(ordered)
x#values[x#id]
else
x#values
}
This won't work, as names is a primitive function and ordered is not an argument for the implicit generic.
How can I make this work under the following conditions:
the names function should keep its original behaviour for all other objects, including objects from other packages.
the code should be acceptable for use in a package
the code should be acceptable by the high standards set by eg Bioconductor.
The generic is available as
> getGeneric("names")
standardGeneric for "names" defined from package "base"
function (x)
standardGeneric("names", .Primitive("names"))
<environment: 0x459c9c0>
Methods may be defined for arguments: x
Use showMethods("names") for currently available ones.
so from the signature you can see that the short answer is that you can't add arguments. You'd definitely not want to create your own function names. A hack would use a package-global variable getOption("pkg_names_ordered") but I wouldn't partake of that solution myself.
In some ways the contract set out by names does not say anything about order (for instance, names and numerical indecies are often used to subset; are the numerical indices for the ordered names, or the unordered names?), so you're really proposing a new generic anyway.

Defining classes at runtime

I am trying to write a function that takes a list of classes (or class names) and returns a class that has all given classes as superclasses. This should return the same class again when given the same list twice, so I am using a hash table for memoization.
I can not use defclass for that purpose as it doesn't evaluate it's DIRECT-SUPERCLASSES parameter. I didn't find any corresponding function in the HyperSpec.
Is there any way I can do this portably?
Just create the DEFCLASS form and evaluate it with EVAL.
You can also use the CLOS function ENSURE-CLASS.

How does one pass multiple data types in llply?

I have a function that requires both a S4 object and a data frame as arguments.
But functions like lapply and llply will only allow one list and one function.
example: new_list=llply(list, function)
I could make a single list with alternating S4 object and data but llply will push one list item at a time which means that it will either be the S4 object or the data (the function cannot perform with just one or the other).
In some sense what I am looking for is akin to a 2D list (where each row has the S4 obj and data and a row gets pushed through at a time).
So how would I make this work?
Here's a more general version of my problem. If I have a function like so:
foobar <- function(dat, threshold=0.5, max=.99)
{
...
}
and I wanted to push a list through this function, I could do:
new_list=llply(list, foobar)
but if I also wanted to pass a non-default value for threshold or max, how would I do so in this context?
Functions like lapply typically have a ... parameter of arguments which get passed to the function. Eg:
lapply(list, foobar, somearg='nondefaultvalue')
If you have multiple varying parameters (eg a different somearg value for each element in list), then you would either pack them as pairs in a list, or turn to a function like mapply:
mapply(foobar, list, somearg=c('vectorof', 'nondefault', 'values')
May be you can try this:
Make each list item itself a list, which contains a S4 object and a data frame.
Just a suggestion, I'm not quite sure if this works.

Resources