Object Model
At this stage the RVTK wrapper is quite working. The end-user can
handle VTK processing pipeline by issuing .Call(...) function with the name of
wrapping function as first argument and R-variables as trailing
parameters. But this quicly would become tedious. It would be more easy
to group functions which belongs to the same class togather. In other
words, the mapping of C++classes to R classes is highly desirable.
I use the object model built on closures as described in the paper of
John M. Chambers and Duncan Temple Lang (R News, 2001,1,3, pp. 17-19).
This paper is somewhat outdated because since R-1.9.1 access to
environment's object through "$" notation was introduced which makes the
use of this sort of object model even more easy.
What in fact we want to do? Since C++ classes are pointers it is
natural to search in R "return by value" world for something similar.
The R-environment looks like just the right thing. Endeed:
> e1<-environment()
> e2<-e1
> e1$z<-1
> e2$z
[1] 1
so e1 and e2 points to the same data storage. This is very like the way
we could copy pointers in C-like languages.
The "inheritance-incapsulation" is easily implemented this way. Suppose
we have object e1 with methods m1 and m2 and object e2 with method m1
inherited from e1, m2-overriden and m3 - new. The code below just do
that we would expect:
e1<-function(.me=environment()){
.me$m1<-function(...){...}
.me$m2<-function(...){...}
return(.me)
}
e2<-function(.me=environment()){
.me<-e1(.me)
.me$m2<-function(...){...}
.me$m3<-function(...){...}
return(.me)
}
.me is a self-refernce to the object (R-environment) itself.
.me<-e1(.me) states that e2 is a child of e1 class, .me$...<-
notation assigns objects in .me environment (functions are particular
case of R-objects).
Thus the parser was trained to output beside C-code corresponding R
code. For C++ class vtkClass
the generator creates vtkClass(.me=environment())
R -function. For Method1 of vtkClass the function in the .me
environment is created.
.me$Method1<-function(arg1,arg2,...){
res<-.Call("R_vtkClass_Method1",.me$obj,arg1,arg2,...)
assign(".VTK.Cache",res)
return(res$.ret.val)
}
obj here is a refernece to VTK C++ class. The VTK class is created and
initialized (with New mwthod) when vtkClass() R-function is called for
the first time. Initialization in fact occurs when vtkClass() function
is called without arguments. .me argument is intended to be used for
inheritance purposes to check the object instance already initialized
and creation of parent class is not required. R-class of return value
(environment of vtkClass() function) is a conctenation of "vtkClass" and
classes of all its ancestors. Note that each method returns only
$.ret.val field of the list returned by .Call(...). All other values can
be read from .VTK.Cache global variable. I do it in this way because it
makes the converting of existing TCL/VTK code more simple - you do not
have to think about appending $.ret.val after the call to RVTK
functions. "Side-effect" return values if they are needed can be read
from .VTK.Cache just after the function call.
So the typical RVTK code should look like this:
vtkClass()->inst1
inst1$Method1()
inst1$DoSomethingElse()