Customize the console printing for S4/RC objects in R - r

In R we can simply type the variable name in the console, the console will automatically print out the value. I have created a new S4/RC class define, and would like to create a nicer way to automatically "print" in the console. How do I edit the console printing functions for a new class?
Here is my code in the console:
ClassA<-setRefClass("ClassA",fields=list(value="numeric"))
"print.ClassA"<-function(object){
cat("--------\n")
cat(object$value,"\n")
cat("--------\n")
}
classobject<-ClassA$new(value=100)
classobject # it doesn't print nicely in the console.
#Reference class object of class "ClassA"
#Field "value":
#[1] 100
print(classobject) # this works
#--------
#100
#--------
My goal is to avoid typing "print" all the time; just type the object name in the console, it will print out nicely, just like calling print().
Thanks!

You need to define a show method for your RefClass object. Read ?setRefClass for details regarding how to write methods. This works:
#the print function: note the .self to reference the object
s<-function(){
cat("--------\n")
cat(.self$value,"\n")
cat("--------\n")
}
#the class definition
ClassA<-setRefClass("ClassA",fields=list(value="numeric"),methods=list(show=s))
classobject<-ClassA$new(value=100)
classobject
#--------
#100
#--------

Related

unused argument error when printing from RC class method

I am creating an RC class and while trying to print(.self$something) within a class method I am getting:
Error in print(.self$something) : unused argument (.self$something)
I am sort of new to R, so am I missing something here?
This is for an assignment which asks us to use RC classes, using R6 is not an option.
myclass <- setRefClass("myclass",
fields = list (
formula = "formula",
data = "data.frame",
something = "numeric"
),
methods = list (
initialize = function(formula, data) {
...
},
print = function() {
...
print(.self$something)
},
)
)
a <- myclass$new(formula,data)
a$print()
> Error in print(.self$something) : unused argument (.self$something)
Edit: Extra info, if I try a$something I get what I should get.
Try to use cat in your print function, you are now in your local print function environment and trying to call your system "print" function. I suggest you use cat as follows:
cat(.self$something)
It will do the job
As #Mohammed mentions, this happened because I was in printing within my own print environment. Though cat() could be an option, later I faced other issues in which cat did not print the object (that could be a thread on its own so I will not go deeper on that here).
What I ended up doing was calling the print function for that specific data type. For instance, if something was a data.frame I called print.data.frame(.self$something) and worked as expected.

print text when calling a model

I hope this is not a double post. I've been looking for an answer.
I have a function that returns a rather big list. So i would like it to print some text in between all the results of the list. A bit as you know it from lm and other models.
Consider this R script
y<-function(z)
{
l<-list()
print("hello world")
l$answer<-2*z
return(l)
}
x<-y(5)
This is a small example. I tried a solution with print but this is a bad solution , simply because it executes print when i save the variable as x<-fun(5). I just want it to execute text when you ask it explicit, or even better,if you can construct your own "summary" command to a list.
Thanks for your time.
If I understood what you want to do , I think you are looking to implement the S3method print.
set the class attribute :"someclass" of the y function return value
define print.someclass
here the code:
y<-function(z)
{
l<-list()
l$answer<-2*z
## Roland comment : usually better to preserve existing classes:
class(l) <- c('someclass', class(l))
return(l)
}
print.someclass<-
function(x,...){ ## add here what you want to print
print("hello world")
}
x<-y(5)
Now when you type x at console or print(x):
x
[1] "hello world"

How to tell an R reference class object to update its method definitions?

I'm looking for a way to tell an instance of a reference class to forget one of its method definitions. For example, I create the class MyReferenceClass and an instance called my_object I can call the method print_hello and everything works:
MyReferenceClass <- setRefClass("MyReferenceClass",
methods = list(
print_hello = function(){
print("hello")
}
)
)
my_object <- MyReferenceClass$new()
my_object$print_hello() # "hello"
If I update the class definition by adding a new method (print_goodbye) my existing object will be able to use it. But if I change a previously defined method (print_hello), it won't update:
MyReferenceClass <- setRefClass("MyReferenceClass",
methods = list(
print_hello = function(){
print("hello_again")
},
print_goodbye = function(){
print("goodbye")
}
)
)
my_object$print_goodbye() # "goodbye" => it works
my_object$print_hello() # "hello" => it doesn't work
Is there a way to tell my_object to forget about its definition of print_hello? This doesn't work: my_object$print_hello <<- NULL
AFAIK the answer is no when trying to inform the object about the class def change "after the fact", i.e. after it has been instantiated/created.
Once you created an instance of a S4 Class, that object is "bound" to the class def as it was when you created the object. And in my opinion this makes perfect sense. Not sure if the "successful" update for formerly missing methods (i.e. print_goodbye()) simply works "by accident" or actually is the desired behavior.
Recommended way to deal with updated class defs
My recommendation: if you decide you want/need to update your class defs, you're just safer off by re-sourcing your entire project code. That way you make sure everything is in place before you create actual instances. I'd consider anything else to be quite a hack that stands on very shaky grounds.
If you decide to hack anyway
There might be some dirty way to hack the hidden .refClassDef object field of an Reference Class instance that actually contains the class def (see my_object$.refClassDef). But setting this field (i.e. using <- on it) didn't work:
my_object$.refClassDef <- MyReferenceClass
Error in envRefSetField(x, what, refObjectClass(x), selfEnv, value) :
'.refClassDef' is not a field in class "MyReferenceClass"
Neither did an explicit assignment via assign():
assign(".refClassDef", MyReferenceClass, my_object)
Error in assign(".refClassDef", MyReferenceClass, my_object) :
cannot change value of locked binding for '.refClassDef'
An even deeper hack would probably involve looking at attributes(my_object$.refClassDef).
There you might find the actual pieces that make up the ref class def. However, I don't know if even changing anything there would be "immediately" reflected.
Also, resetClass() might give you some more insights.
UPDATE: 2014-03-19
For handling your caching-approach two approaches come to mind:
1. The most evident way: use copy()
See ?setRefClass
MyReferenceClass <- setRefClass("MyReferenceClass",
methods = list(
print_hello = function(){
print("hello")
}
)
)
my_object <- MyReferenceClass$new()
MyReferenceClass <- setRefClass("MyReferenceClass",
methods = list(
print_hello = function(){
print("hello_again")
},
print_goodbye = function(){
print("goodbye")
}
)
)
Before copying:
my_object$print_hello()
[1] "hello"
After copying:
my_object <- my_object$copy()
my_object$print_hello()
[1] "hello_again"
2. Hacking at attributes(my_object$.refClassDef)$refMethods (OUTLINE, NOT WORKING YET)
Even though I wouldn't recommend actually relying on something like this, hacks are always a great way to get a deeper understanding of how things work.
In this case, we could try to modify attributes(my_object$.refClassDef)$refMethods which is an environment that contains the actual method defs as I'm guessing that this is where the object "looks" when a method is called.
It's no problem overwriting the actual method defs, yet it seems to have no immediate effect. I'm guessing that there are more "links" to the "old" class def involved that would need to be updated manually in a similar way.
Note that my_object still features the method print_hello that prints "hello":
attributes(my_object$.refClassDef)$refMethods$print_hello
Class method definition for method print_hello()
function ()
{
print("hello")
}
This is how an overwriting function might look like:
ensureRecentMethods <- function(obj, classname) {
## Get generator //
gen <- getRefClass(classname)
## Get names of methods belonging to the class of 'obj' //
## This will serve as an index for the update
idx1 <- names(Filter(function(x) {attr(x, "refClassName") == class(obj)},
as.list(attributes(obj$.refClassDef)$refMethods))
)
#idx2 <- names(Filter(function(x) {attr(x, "refClassName")==gen$className},
# as.list(gen$def#refMethods)
#))
## Note:
## 'idx2' could be used to enforce some validity checks such as
## "all old methods must also be present in the updated class def"
## Overwrite //
for (ii in idx1) {
## Note how we are overwriting the old method defs in environment
## 'attributes(obj$.refClassDef)$refMethods' with the updated
## definitions taken from the generator of the updated class
## 'gen$def#refMethods[[ii]]' by making use of the index retrieved
## one step before ('idx1')
expr <- substitute(
assign(x=X, value=VALUE, envir=ENVIR),
list(
X=ii,
VALUE=gen$def#refMethods[[ii]],
ENVIR=attributes(obj$.refClassDef)$refMethods
)
)
eval(expr)
}
## As at the end of the day ref class objects are nothing more than
## environments, there is no need to explicitly return the actual
## ref class object 'obj' as the original object has already
## been updated (pass-by-reference vs. pass-by-value)
return(TRUE)
}
Applying it:
ensureRecentMethods(obj=my_object, classname="MyReferenceClass")
Even though the def of print_hello was indeed overwritten, the object still grabs the "old" version somehow:
attributes(my_object$.refClassDef)$refMethods$print_hello
## Note the updated method def!
Class method definition for method print_hello()
function ()
{
print("hello_again")
}
my_object$print_hello()
[1] "hello"
Take advantage of my_class#generator$def#refMethods
How about including an update method in the original class, as did here,
Manual modifications of the class definition of a Reference Class instance

r reference classes - do they have static field members/variables?

I have been playing a little with R's R5 class system to see what it can and can't do. In that process I have stumbled upon what looks like static class field members (which does not appear to be in the documentation - but i could have missed it)
[2014 update]
Warning !!! : The following code does not work with R version >= 3.0
This post, its answers and particularly the comments provide useful insights and reminders about the R5 OO-system and the R language in general. However it is probably a bad idea to cultivate the idiom of using the environment of the R5 class instances directly.
[end 2014 update]
In the following code, the first field is the classic definition of an instance field variable. The second definition appears to create a static class field using an accessor method. I would like to know if this use is kosher (or is my code example simply coincidental). The third field use creates a quasi-private instant field variable using an accessor method.
assertClass <- function(x, className, R5check=FALSE) {
# simple utility function
stopifnot(class(x)[1] == className)
if(R5check) stopifnot(is(x, 'envRefClass'))
}
A <- setRefClass('A',
fields = list(
# 1. public, typed, instance field
myPublicInstanceVar = 'character',
# 2. this assignment appears static
# but if the field me.static.private
# was declared in the field list
# it would be a local instance var
myPrivateStaticVar = function(x) {
if (!missing(x)) {
assertClass(x, 'character')
me.static.private <<- x
}
me.static.private
},
# 3. quasi-private, typed, instance field
myPrivateInstanceVar = function(x) {
if (!missing(x)) {
assertClass(x, 'character')
.self$me.private <<- x
}
.self$me.private
}
),
methods = list(
initialize = function (c='default') {
myPublicInstanceVar <<- c
myPrivateStaticVar <<- c
myPrivateInstanceVar <<- c
}
)
)
# test instantiation
instance1.of.A <- A$new('first instance')
str(instance1.of.A)
instance2.of.A <- A$new('second instance')
str(instance1.of.A)
str(instance2.of.A)
instance3.of.A <- getRefClass('A')$new('third instance')
instance3.of.A$myPrivateStaticVar <- 'Third instance - changed'
print(instance1.of.A$myPrivateStaticVar)
print(instance2.of.A$myPrivateStaticVar)
print(instance3.of.A$myPrivateStaticVar)
str(instance1.of.A)
str(instance2.of.A)
str(instance3.of.A)
# but not really private ...
instance1.of.A$myPublicInstanceVar # works
instance1.of.A$me.static.private # DOES NOT WORK - where is this variable stored
instance1.of.A$me.private # works
# till death do us part
instance3.of.A <- NULL
gc()
str(instance1.of.A)
str(instance2.of.A)
str(instance3.of.A)
If you run this code - you can see that the second field variable appears to operate as a static class member. What is less clear to me is where the reference class keeps this field (hence my comment in the penultimate line above).
The short answer - based on Hadley's comments above - is no. R's reference classes do not have static variables.

Documentation of squared bracket `[` function

I have a function in R that looks somewhat like this:
setMethod('[', signature(x="stack"),definition=function(x,i,j,drop){
new('class', as(x, "SpatialPointsDataFrame")[i,]) })
I use it to get a single element out of a stacked object. For the package I'm building I need a .Rd file to document the function. I stored it as [.Rd but somehow the R CMD check does not see this. It returns:
Undocumented S4 methods: generic '[' and siglist 'MoveStack,ANY,ANY'
The [.Rd file starts with these lines:
\name{[}
\alias{[}
\alias{[,stack,ANY,ANY-method}
\docType{methods}
\title{Returns an object from a stack}
\description{Returning a single object}
\usage{
\S4method{\[}{stack,ANY,ANY}(x,i,y,drop)
}
Any idea how I make R CMD check aware of this file?
If you look at the source code of the sp package, for example SpatialPolygons-class.Rd, the Methods section:
\section{Methods}{
Methods defined with class "SpatialPolygons" in the signature:
\describe{
\item{[}{\code{signature(obj = "SpatialPolygons")}: select subset of (sets of) polygons; NAs are not permitted in the row index}
\item{plot}{\code{signature(x = "SpatialPolygons", y = "missing")}:
plot polygons in SpatialPolygons object}
\item{summary}{\code{signature(object = "SpatialPolygons")}: summarize object}
\item{rbind}{\code{signature(object = "SpatialPolygons")}: rbind-like method}
}
}
method for [ is defined.
Name and class of the file are
\name{SpatialPolygons-class}
\alias{[,SpatialPolygons-method}
If you look at the help page for ?SpatialPolygons you should see
> Methods
>
> Methods defined with class "SpatialPolygons" in the signature:
>
> [ signature(obj = "SpatialPolygons"): select subset of (sets of)
> polygons; NAs are not permitted in the row index
>
So I would venture a guess that if you specify a proper (ASCII named) file name, give it an alias as in the above example, you should be fine.

Resources