Resources

SAS® AppDev Studio 3.0 Developer's Site

Passing Lists

Passing an SCL List to Java

This page documents rules (or at least guidelines) for creating and returning SCL lists from SCL methods (executing in the SAS server) to a Java client or other remote.

When using remote SAS server objects from a Java client, you may declare your methods in a remote interface using either

   void method(input-arguments, ...);

or

   returnType method(input-arguments, ...);

In SCL Version 6.12, SCL does not support returning values from methods, so all SCL methods are effectively void. The convention for Java methods that have non-void return types is that the return value is the first parameter of the SCL method. The return parameter is treated as an output parameter. All other method parameters are input only.

label: method return-parameter 8 input-parameters...;
   ...
endmethod;

SCL methods "return" a value by assigning to the first parameter.

SCL lists are passed as numeric parameters. The data types allowed are basically numbers (doubles), Strings, and HListInterface.

Thus, an SCL method may create and return an SCL list to the Java caller:

Java interface:

  public interface SCLListsInterface {
     HListInterface newList(double size);

and the SCL implementation:

  newList: method result 8 size 8;
     result = makelist(size);
  endmethod;

The problem with this simple implementation is that on each call to the newList method, a new SCL list is created and never deleted.

An HListInterface in the Java client corresponds to an SCL list in the SAS server running SCL. However, whereas Java does automatic memory management (such as garbage collection), there is no garbage collection in SCL. Lists cannot be freely created whenever requested by a remote Java client. The SCL class must manage the lists it creates, and delete lists no longer in use.

Here are some guidelines:

  1. The SAS marshaling subsystem is to non-recursively free all lists it creates, see pseudo-code example below:
    SAS-Marshaling subsystem:
    read SAS/Connect packet
    create lists to call method
    call SCL method
    write return packet
    delete all lists created here with no recursive deletes
    
  2. The SCL methods free lists they create as in the example below, keep track of them, and don't expect the consumer to ask them to free them on their behalf, nor return the handles to them. The free should occur on subsequent calls or _TERM_.
    MODEL.SCL
    
        /* SAMPLE METHOD */
        /* GET DATA */
        /* outlist = remoteobject.getdata(start,end); */
        getdata: method out_datavec 8 in_startobs 8 in_endobs 8;
    
          /* start every method */
          link MakeGlocalList;
    
          /* set return handle to the list */
          out_datavec = reuselist;
          do i = in_startobs to in_endobs;
    	 rc = insert...
          end;
    
        endmethod;
    
        /* overridden _TERM_ method */
        subterm:
          link GarbageCollector;
          call super(_self_,_method_);
        endmethod;
    
        /* MAKEGLOBALLIST: create a 'remembered' list handle */
        MakeGlobalList:
          link GarbageCollector;
          reuselist = makelist();
        return;
    
        /* GARBAGECOLLECTOR: clean up */
        GarbageCollector:
          /* free any lists from last call, "reuselist" is an instance attr
          */
          if reuselist > 0 then
    	do;
    	  rc = dellist(reuselist,'Y');
    	  reuselist=0;
    	end;
        return;
    
  3. Although not absolutely necessary, we highly recommend that well behaved new SCL models are to use OutputList, or any other return value primitives such as CHAR and NUM, exclusively and not depend on Update parameters. Parameters other than the return value are to be treated as input parameters as in the above example.
  4. If the same models are used by SAS/AF clients directly rather than wrappers or underlying classes, then the clients are to consume values or make local copies before subsequent calls to the model if they do not create the lists for the model, as in this example.
    VIEWER.SCL
    
        call SEND(model,'getNewPosition',pos);
        xCoordinate = getNitem(pos,1);
        yCoordinate = getNitem(pos,2);
    
        call SEND(model,'getNewSize',sz);
        mysz = copylist(sz,'Y');
        ...
        /* much later */
        width = getNitem(mysz,1);
        height = getNitem(mysz,2);
        rc = dellist(mysz,'Y');
    
  5. V6 optimization only: the models should recognize client allocation of the return value lists as in the example below. For V7, this is no longer applicable with RETURN= new SCL syntax
    MODEL.SCL
    
        getstuff: method out 8 parm1 $ parm2 $;
        /* free any lists from the last call */
        if reuselist > 0 then
          do;
    	reuselist = dellist(reuselist,'Y');
    	reuselist = 0;
          end;
    
        /* if the user gave us a list use it and do not create a
        * tagged list
        */
        if out < 1 then
          do;
    	reuselist = makelist();
    	out = reuselist;
          end;
        rc = insert(out,...
    
    VIEW.SCL
    
        mylist = makelist();
        Call SEND(model,'getStuff',mylist,'Neat','Stuff');
    

Using the above rules there are two significant benefits:

  1. no list leaks, and
  2. daisy-chaining the methods through middleware is acceptable.

Printing Lists

The HListInterface defines a print method, and the HList class (the implementation of HListInterface) implements the print method, but this method prints with no line breaks, so the output is somewhat hard to decipher. Below is a Java method for printing a list to a PrintWriter such as System.out:

public static void print(PrintWriter out, HListInterface l)
{
   for(int i=0;i<l.count();i++) {
      HListItem child = l.getItem(i);
      String childName = l.getName(i);
      if(child instanceof ListItem) {
          HListInterface childList = l.getList(i);
          out.println("Walking child list:" + childList);
          print(out, childList);
      }
      else if(child instanceof StringItem) {
          String childString = l.getString(i);
          out.println("String child=" + childString);
      }
      else if(child instanceof DoubleItem) {
          double childDouble = l.getDouble(i);
          out.println("Double  child=" + childDouble);
      }
   }
}