[R] Change value of a slot of an S4 object within a method.

Joris Meys jorismeys at gmail.com
Wed Aug 25 19:21:17 CEST 2010


Hi Steve,

thanks for the tip.  I'll definitely take a closer look at your
solution for implementation for future use.  But right now I don't
have the time to start rewriting my class definitions.

Luckily, I found where exactly things were going wrong. After reading
into the documentation about the evaluation in R, I figured out I have
to specify the environment where substitute should look explicitly as
parent.frame(1). I still don't understand completely why exactly, but
it does the job.

Thus :
eval(eval(substitute(expression(object at extra[[name]] <<- value))))

should become :

eval(
   eval(
      substitute(
         expression(object at extra[[name]] <<- value)
      ,env=parent.frame(1) )
   )
)

Tried it out and it works.

Cheers
Joris

On Wed, Aug 25, 2010 at 6:21 PM, Steve Lianoglou
<mailinglist.honeypot at gmail.com> wrote:
> Hi Joris,
>
> On Wed, Aug 25, 2010 at 11:56 AM, Joris Meys <jorismeys at gmail.com> wrote:
>> Dear all,
>>
>> I have an S4 class with a slot "extra" which is a list. I want to be
>> able to add an element called "name" to that list, containing the
>> object "value" (which can be a vector, a dataframe or another S4
>> object)
>>
>> Obviously
>>
>> setMethod("add.extra",signature=c("PM10Data","character","vector"),
>>  function(object,name,value){
>>             object at extra[[name]] <- value
>>  }
>> )
>>
>> Contrary to what I would expect, the line :
>> eval(eval(substitute(expression(object at extra[[name]] <<- value))))
>>
>> gives the error :
>> Error in object at extra[[name]] <<- value : object 'object' not found
>>
>> Substitute apparently doesn't work any more in S4 methods...
>>
>>  I found a work-around by calling the initializer every time, but this
>> influences the performance. Returning the object is also not an
>> option, as I'd have to remember to assign that one each time to the
>> original name.
>>
>> Basically I'm trying to do some call by reference with S4, but don't
>> see how I should do that. How would I be able to tackle this problem
>> in an efficient and elegant way?
>
> In lots of my own S4 classes I define a slot called ".cache" which is
> an environment for this exact purpose.
>
> Using this solution for your scenario might look something like this:
>
> setMethod("add.extra",signature=c("PM10Data","character","vector"),
> function(object, name, value) {
>  object at .cache$extra[[name]] <- value
> })
>
> I'm not sure what your entire problem looks like, but to "get" your
> extra list, or a value form it, you could:
>
> setMethod("extra", signature="PM10Data",
> function(object, name=NULL) {
>  if (!is.null(name)) {
>    object at .cache$extra[[name]]
>  } else {
>    object at .cache$extra
> })
>
> ... or something like that.
>
> The last thing you have to be careful of is that you nave to make sure
> that each new("PM10Data") object you have initializes its *own* cache:
>
> setClass("PM10Data", representation(..., .cache='environment'))
> setMethod("initialize", "PM10Data",
> function(.Object, ..., .cache=new.env()) {
>  callNextMethod(.Object, .cache=.cache, ...)
> })
>
> Does that make sense?
>
> --
> Steve Lianoglou
> Graduate Student: Computational Systems Biology
>  | Memorial Sloan-Kettering Cancer Center
>  | Weill Medical College of Cornell University
> Contact Info: http://cbio.mskcc.org/~lianos/contact
>



More information about the R-help mailing list