[R] proto: make a parameter persist

Gabor Grothendieck ggrothendieck at gmail.com
Tue Feb 21 15:01:34 CET 2012

On Tue, Feb 21, 2012 at 12:15 AM, Ben quant <ccquant at gmail.com> wrote:
> Thanks again for your so far on proto. I have another question.
> What is the best way to "do stuff" based on data prior to calling a
> function? I tried the code below without expr (and including commas after
> data member assignments), but it errors out. I'd like to make decisions
> based on inputs during proto object construction and prep my data_members
> for use in the functions that (would) follow. I think I could probably get
> around this with a small function with other functions within the same proto
> object, but I'd rather not repeat that in each function...if that makes
> sense. See my last line of code below:
> makeProto = proto( expr={
>   data_member1=NULL
>   data_member2=5
>   data_member3=NULL
>   if(!is.null(data_member1)){
>     with(.,data_member3 = data_member1 + data_member2)
>   }
> })
> oo = makeProto$proto()
> oo$data_member1 # NULL
> oo$data_member2 # 5
> oo$data_member3 # NULL
> oo2 = makeProto$proto(data_member1 = 7)
> oo2$data_member1 # 7
> oo2$data_member2 # 5
> oo2$data_member3 # I want this to be 12 (12 = 7 + 5), but I get NULL
> Its late for me so hopefully this makes sense...

There are multiple issues here:

1. The expr is executed at the time you define the proto object -- its
not a method.  Once the proto object is defined the only thing that is
left is the result of the computation so you can't spawn a child and
then figure that this code will be rerun as if its a constructor.  You
need to define a constructor method to do that.

2. You can't use dot as if it were a special notation -- its not.  A
single dot is just the name of an ordinary variable and is not
anything special that proto knows about.  In the examples where dot is
used its used as the first formal argument to various methods but this
was the choice of the method writer and not something required by
proto.  We could have used self or this or any variable name.

3. Note that the code in expr=... is already evaluated in the
environment of the proto object so you don't need with.

4. I personally find it clearer to reserve = for argument assignment
and use <- for ordinary assignment but that is mostly a style issue
and its up to you:

5. The discussion of traits in the proto vignette illustrates
constructors -- be sure to read that.  Traits are not a special
construct built into proto but rather its just a way in which you can
use proto.   That is one of the advantages of the prototype model of
OO -- you don't need to have special language constructs for many
situations where ordinary OO needs such constructs since they are all
subsumed under one more general set of primitives.

Here we define the trait MakeProto (again, traits are not a special
language feature of proto but are just a way of using it):

MakeProto <- proto(
   new = function(., ...) {
      .$proto(expr = if ( !is.null(d1) ) d3 <- d1 + d2, ...)
   d1 = NULL,
   d2 = 5,
   d3 = NULL

oo <- MakeProto$new()
oo$d1 # NULL
oo$d2 # 5
oo$d3 # NULL

oo2 <- MakeProto$new(d1 = 7)
oo2$d1 # 7
oo2$d2 # 5
oo2$d3 # 12

In the above oo$d1, oo$d2, oo$d3 are actually located in MakeProto and
delegated to oo so that when one writes oo$d2 it looks into MakeProto
since it cannot find d2 in oo.  oo2$d2 is also not in oo2 but
delegated from MakeProto; however, oo2$d1 and oo2$d3 are located in
oo2 itself.  That is due to the way we set it up and we could have set
it up differently.  Try str(MakeProto); str(oo); str(oo2) to  see

Statistics & Software Consulting
GKX Group, GKX Associates Inc.
tel: 1-877-GKX-GROUP
email: ggrothendieck at gmail.com

More information about the R-help mailing list