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.
Related
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)
}
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.
Is it ok from architectural point of view to dispatch the constructor in R (S3 system)?
I have a constructor for class returns and I want to dispatch it in a way like: returns.zoo, returns.data.frame etc.
Just my opinion, but I think there is (unwritten) convention to use as prefix in this case. For example: as.data.frame coerces various objects to a data frame.
Same with as.matrix, as.Date and as.list ...
Often a "non-as" function calls the generic as function (e.g. data.frame function calls as.data.frame).
There is also a good practice to implement a function with is prefix.
For example: is.data.frame, is.list.
But sometimes this is not so. For example formula is a generic "coercer"
and as.formula is not. And there are a lot of packages with combined practice. For example igraph includes as.igraph generic but uses from_data_frame to create object from a data frame.
So I guess as.returns.zoo will look aligned with existing practice but
returns.zoo is not wrong either.
I'd like to be able to view the structure of objects in Matlab/GNU Octave the same way as I do in R (using the str() function). Is there a function that does this? An example task would be returning nr rows and cols in matrix, but also all the arguments for a given function.
I'm aware that I could use both size() and help() (but not for function files) separately to get this information.
There are several useful functions for displaying some information about Matlab objects (I can't say anything about Octave compatibility), but I'm not sure they'll provide the same detail as R's str(). You can display all of the methods of a class with the methods function, e.g.:
methods('MException')
which returns
Methods for class MException:
addCause getReport ne throw
eq isequal rethrow throwAsCaller
Static methods:
last
The what function will return similar results. Or methods can be used on an object of a given class:
ME = MException('Test:test','Testing');
methods(ME)
Similarly, you can view the properties with properties and the events with events.
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.