A COM interface to the S evaluator


COM Containers in S

We are used to using containers in other COM clients. For example, in Excel the Workbooks and the Worksheets classes are containers for elements of the class Workbook and Worksheet respectively. The container supports a reasonably standard interface, providing properties/methods Item, Count, Add and Delete.

Now, suppose we want to implement a similarl concept in S. In our case, we might create a general class definition for this and provide the methods for any type of container.

COMContainerGenerator = 
function(elementDefn) {

 .containerElements = list()

 newElement = function() {
   .Call("R_RCOMSObject", elementDefn, PACKAGE = "RDCOMServer")
 }

 add = function() { # before, after, count, type
   n = length(.containerElements)
   tmp = newElement()
   .containerElements[[n+1]] <<- tmp
   tmp
 }

 count = function() {
   length(.containerElements)
 }

 delete = function(which) {
  .containerElements <<- .containerElements[-which]
  TRUE 
 }

 item = function(which) {
  .containerElements[[which]]
 }

 list(Item = item, Delete = delete, Count = count, Add = add)
}

We can use these generic methods to provide a container object in S. We can define a COM container class for S that stores definitions of particular container types.
setClass("SCOMContainerClass", representation("SCOMClass",
                                              elementDefintion = "SCOMClass"))
SCOMContainerClass = 
function(elementDefn, name, help = "", def = new("SCOMContainerClass"), where = "")
{
  def = .initSCOMClas(def, name = name, help=help) 
  def@elementDefinition = elementDefn
}
Now we can define a method for createCOMObject that creates a container.
setMethod("createCOMObject", 
           "SCOMContainerClass",
           function(def) {
	    funcs = COMContainerGenerator(def@elementDefinition)
            obj = COMSIDispatchObject(funcs)            
            .Call("R_RCOMSObject", obj, PACKAGE="RDCOMServer")
           })
So now let's look at an example. Suppose we want to have a container of elements of Normal distributions, e.g the SNormal class defined in Sobject.xml. We will assume that this class is already registered and that we know its UUID, <uuid>c484d2f9-21f5-49ac-8c8d-2007e12245d3</uuid>.
edef = GetCOMClassDef("{c484d2f9-21f5-49ac-8c8d-2007e12245d3}"
def = SCOMContainerClass(edef, "NormalManager")
registerCOMClass(def)
Now, clients can create instances of this container.
mgr = Win32::OLE->new("NormalManager");

%params = ('AB' => {0, 10}, 'CD' => {1, 3}, 'OK' = {-10, 2});
foreach $i keys($parms))