From jon.clayden at gmail.com  Tue Oct 26 13:57:46 2010
From: jon.clayden at gmail.com (Jon Clayden)
Date: Tue, 26 Oct 2010 12:57:46 +0100
Subject: [Rd] Reference classes
In-Reply-To: <AANLkTinrSDJ6ZxinQNF3F9EVnnU=x0VeaxYoq6+t41fe@mail.gmail.com>
References: <AANLkTik+o=SgwXO5augahHC18Hv9hBL87VOyGVG8LqN_@mail.gmail.com>
	<4CC1CFFE.5080402@r-project.org>
	<AANLkTinrSDJ6ZxinQNF3F9EVnnU=x0VeaxYoq6+t41fe@mail.gmail.com>
Message-ID: <AANLkTinYqjXnO97aM19PhR+V8-qdOrE=jPeXOYFpAe3Z@mail.gmail.com>

On 23 October 2010 00:52, Jon Clayden <jon.clayden at gmail.com> wrote:
> On 22 October 2010 18:55, John Chambers <jmc at r-project.org> wrote:
>
>>> As a suggestion, it would be nice if the accessors() method could be
>>> used to create just "getters" or just "setters" for particular fields,
>>> although I realise this can be worked around by removing the unwanted
>>> methods afterwards.
>>
>> In other words, read-only fields. ?There is a facility for that implemented
>> already, but it didn't yet make it into the documentation, and it could use
>> some more testing. ?The generator object has a $lock() method that inserts a
>> write-once type of method for one or more fields. ?Example:
>>
>>> fg <- setRefClass("foo", list(bar = "numeric", flag = "character"),
>> + ? ? ? ? ? ? methods = list(
>> + ? ? ? ? ? ? addToBar = function(incr) {
>> + ? ? ? ? ? ? ? ? b = bar + incr
>> + ? ? ? ? ? ? ? ? bar <<- b
>> + ? ? ? ? ? ? ? ? b
>> + ? ? ? ? ? ? }
>> + ? ? ? ? ? ? ))
>>> fg$lock("bar")
>>> ff = new("foo", bar = 1.5)
>>> ff$bar <- 2
>> Error in function (value) ?: Field "bar" is read-only
>>
>> A revision will document this soon.
>>
>> (And no, the workaround is not to remove methods. ?To customize access to a
>> field, the technique is to write an accessor function for the field that, in
>> this case, throws an error if it gets an argument. ?See the documentation
>> for the fields argument. ?The convention here and the underlying mechanism
>> are taken from active bindings for environments.)
>
> OK, yes - I see. This is clearly much less superficial than removing
> the setter method for a field which can be directly set anyway. I'll
> have to try out field accessor functions and get a feel for the
> semantics.

Unfortunately, I'm having difficulty working out the accessor function
approach. I've looked in the Rcpp package for examples, but it doesn't
seem to use this feature. If I define

Foo <- setRefClass("Foo", fields=list(bar=function (newBar) {
                                            if (missing(newBar)) bar
                                            else stop("bar is read-only") }),
                          methods=list(barExists=function ()
print(exists("bar"))))

then I can't access the value of "bar" due to infinite recursion.
Using ".self$bar" in the accessor produces the same effect.

> f <- Foo$new()
> f$barExists()
[1] TRUE
> f$bar
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?
> f$bar()
Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

I can guess why this is happening (accessing "bar" within the accessor
calls itself), but how can I get at the value of "bar" within the
accessor without this occurring?

The other problem is that I can't even set a value at the time of
creation of the object, viz.

> f <- Foo$new(bar=2)
Error in function (newBar)  : bar is read-only

Is there a way to test whether "bar" has already been set in the
accessor, so that I can allow it to be set once? (I know lock() allows
this, but it would be useful to be able to replicate the effect using
accessors, so that it can be generalised further where needed.)
Clearly, exists("bar") doesn't do this, as seen above -- presumably
because it sees the method rather than the field, or there is some
default value.

Thanks in advance,
Jon



[Rd] Reference classes
Jon Clayden