Example: Creating An Object-Oriented Application in SCL |
The routines that use DDATA and FDATA are very similar. In fact, the set of methods for each class is similar by design. The actual implementations of the methods differ. For example, the CPY method in DDATA is different from the CPY method in FDATA, but the basic concept of reading character data is the same. In effect, the interface for both classes is essentially the same.
You can exploit this similarity to make it easier to use the two classes. In fact, you can have one data loop that handles both types of classes by defining an SCL interface for both classes. To define the interface, you generalize the functionality and create the following SCL entry:
interface reader; read: method return=num; cpy: method n: num return=string; endinterface;
Use SAVECLASS to create an interface entry with two abstract methods, READ and CPY. The abstract methods are by definition the interface itself. Any class that supports this interface will need to supply the implementations for these methods.
When you use the SAVECLASS command in an SCL entry that contains a CLASS block, the class is generated and its CLASS entry is created. This is the equivalent of using the Class Editor to interactively create a CLASS entry.
Once you have created the interface, you must modify the DDATA and FDATA classes to support it. To do that, change the CLASS statements in each class as follows:
class ddata extends data supports reader;
and
class fdata extends data supports reader;
Since DDATA and FDATA contain READ and CPY methods, no other changes are needed in the classes.
To use the new interface, you will create two helper classes. One is an iterator class that will be used to abstract the looping process over both DDATA and FDATA. Use the following code to create the two helper classes:
class iter; private num varn nvars; public reader r /(autocreate='n'); /* Constructor */ iter: method rdr: reader n: num; varn = 1; nvars = n; r = rdr; endmethod; /* Check if there are more elements to iterate over */ more: method return=num; dcl num more = ^r.read(); varn = 1; return more; endmethod; /* Return the next element */ next: method return=string; dcl string c = ""; c = r.cpy(varn); varn + 1; return c; endmethod; endclass;
Several things require explanation for this class. First, note that it has two private variables, varn and nvars, to keep track of where it is in the iteration process.
It also has a variable r which is an interface type. Since we cannot create the interface automatically when an example of ITER is created, we specify the AUTOCREATE='N' option.
The iterator has three methods. In the first method, the constructor stores the reader variable and the number of variables in the reader. A reader variable is any class that supports the READER interface. The MORE method reads from the reader to check whether there are any more elements. The NEXT method returns the next element.
The other helper class uses the iterator to loop over the data in a reader.
class read; private iter i; read: method r: reader; i = _new_ iter(r, 2); endmethod; loop:method; do while(i.more()); dcl string s s2; s = i.next(); s2 = i.next(); put s s2; end; endmethod; _term: method /(state='O'); i._term(); _super(); endmethod; endclass;
The constructor will create a new iterator, and the LOOP method will use it to loop over the data.
The SCL to use these classes is
init: dcl string filename; dcl fdata f; dcl ddata d; dcl read r; /* Read an external file */ filename = "some_file"; f = _new_ fdata(filename, "i"); r = _new_ read(f); r.loop(); r._term(); /* Read a data set */ filename = "sasuser.x"; d = _new_ ddata(filename, "i", 2); r = _new_ read(d); r.loop(); r._term(); return;
This code will successively read an external file and a data set.
Copyright © 2009 by SAS Institute Inc., Cary, NC, USA. All rights reserved.