Previous Page | Next Page

Example: Creating An Object-Oriented Application in SCL

Using SCL Class Syntax with SAS/AF Software

So far you have created stand-alone SCL classes. SCL class syntax can be used to create SAS/AF visual objects.

This exercise will extend the SAS/AF List Box class. The readers that were previously developed in this tutorial will be used to read data that will be used to initialize the items in the List Box.

To extend the List Box class, you must write a class to extend List Box and modify the READ class that was created in Other Classes and Further Abstraction. The READ class will then be able to pass the new class to the list box to use for initializing the item list instead of having it simply print the character data after reading it.

You must create a new interface and make a minor modification to the LOOP method in READ.

The interface has a single method, CALLBACK:

interface call;
 callback: method s:string;
endinterface;

The modified LOOP method in READ is

loop: method caller:call;
       do while(i.more());
         caller.callback(i.next());
       end;
   endmethod;

The method now takes a CALL interface parameter and calls its CALLBACK method.

Note:   You do not specify the implementation of a method in an interface; you simply supply the name and parameter list.  [cautionend]

It is not necessary to know what the implementation for CALLBACK is at this point, only that you call it in the read loop and pass a character value to it. Whatever class supports the interface will supply the implementation for CALLBACK.

Now, create the extended List Box class (depending on which version of SAS you have, you may need to create an empty MLIST class first in order for the following to work).

import sashelp.classes;
class mlist extends listbox_c supports call;

   /* Local item list */
   private list listid;

   /* Set method */
   set: method r: read;
        listid = makelist();
        r.loop(_self_);
   endmethod;

   /* Store the character value in the local list */
   callback: method s:string;
             rc = insertc(listid, s, -1);
   endmethod;

   /* Set the items attribute */
   setattr: method;
            _self_.items = listid;
   endmethod;

endclass;

Note how the IMPORT statement and the LOOP, SET, SETATTR, and CALLBACK methods will be used:

To see how this works, create the CALL interface, as well as the classes READ and MLIST, by using the SAVECLASS command. Then edit a frame. In the Components window, add the MLIST class to the class list (via AddClasses on the pop-up menu). After it appears on the list, drag and drop MLIST to the frame. In the frame's source, enter

init:
 dcl ddata d;
 dcl read r;
 dcl string filename = "sasuser.x";
 d = _new_ ddata(filename, "i", 2);
 r = _new_ read(d);
 mlist1.set(r);
 mlist1.setattr();
 return;

This will create a DDATA reader with an associated READ class. Now call the SET and SETATTR methods on the new List Box class (MLIST).

Compile and use the TESTAF command on the frame. The initial list of items will be

San Francisco 
Honolulu 
New York 
Miami 


Flexibility

Using the CALL interface in the above exercise allows a great deal of flexibility in modifying the MLIST and READ classes.

For example, to process numeric data instead of character data, you could simply overload the CALLBACK method in the interface

interface call;
 callback: method s:string;
 callback: method n:num;
endinterface;

and support it in the MLIST class

 callback: method n:num;
           /* process numeric value */
 endmethod;

Now, the READ class - or any class that supports CALL - can call the CALLBACK method with a numeric parameter. Clearly, this process can be generalized to make use of any possible parameter lists that are needed for CALLBACK.

Another feature is that any class that supports the READER interface can be used to read the data into the list box. For example, to use an external file, change the frame's SCL to

init:
 dcl fdata f;
 dcl read r;
 dcl string filename = "some_file";
 f = _new_ fdata(filename, "i");
 r = _new_ read(f);
 mlist1.set(r);
 mlist1.setattr();
 return;

We can consolidate the code further by creating another class to set up the reader:

init:
 dcl SetReader g = _new_ SetReader();
 dcl read r = g.get();
 mlist1.set(r);
 mlist1.setattr();
 return;

SetReader sets up whatever reader is necessary even if your program is using external data. Then, at the frame level, you can read from any type of data source, such as a data set, an external file, an SCL list, or any other user-defined data source. The only requirement is that SetReader support the reader interface.

Previous Page | Next Page | Top of Page