Example: Creating An Object-Oriented Application in SCL |
In this exercise you will read a simple SAS data set that contains two character variables. You will learn how to open the data set, fetch an observation, copy a data set character variable, and close the data set. The SCL functions that will be used are
You will build a class that encapsulates these operations so that they can be called as methods on any given data set. Because of this, the class itself should represent a data set.Before you can begin converting these functions to class methods, you must create the class data, as shown in the next section, Class Data.
Class Data |
Class data is declared with the DCL statement by using the following code:
class x; dcl num n; endclass;
Here class X contains a numeric variable called n.
The DCL statement can be omitted when you provide a variable scope modifier such as public, private or protected. Scope modifiers indicate how the variable is to be accessed from locations outside the class. By default, the scope modifier is public, which indicates that anyone can access the variable. Both private and protected scope modifiers restrict access to the variable.
The Data Set Class |
For the data set class, begin with the following class data:
class DDATA; public string dname; public string mode; protected num fid; protected num nvars; endclass;
where
dname | |
mode | |
fid |
is the file identifier that will be returned from the OPEN call |
nvars |
You will create one method for each of the SCL functions OPEN, FETCH, GETVARC, and CLOSE. The following example shows how to use the FETCH function to take an action that is based on the value of its return code:
read: method return=num; dcl num rc; rc = fetch(fid); return rc; endmethod;
You can use a function such as GETVARC directly in the IF statement. In this case, the VARTYPE function is executed, and then the IF expression evaluates the return code to determine whether to perform the conditional action. The following method takes a parameter n, which represents the variable number, and returns the character variable c from GETVARC.
cpy: method n: num return=string; dcl string c = ""; if (vartype(fid, n) = 'C') then c = getvarc(fid, n); return c; endmethod;
CLOSE is used to close a data set as soon as it is no longer needed by the application. The method in this example for CLOSE is
_term: method /(state='O'); if (fid) then close(fid); _super(); endmethod;
This method closes the data set represented by fid. It also contains two items that refer to the parent class of DDATA (State='O' and _super()). A parent class is the class from which a particular class was extended or derived. In this case, DDATA was implicitly extended from OBJECT.CLASS. Since OBJECT.CLASS contains a _term method, you must indicate that you are overriding it in DDATA by specifying State='O'. Because OBJECT.CLASS is being overridden, to ensure that the _term method in OBJECT.CLASS is still executed, use the function call _super().
Constructors |
The method that will be used for opening the data set is called a constructor. A constructor is a method that is used to instantiate a class and provides a way for initializing class data. In order for a method to be a constructor, it must be a void method (one that does not have a return value), and it must have the same name as the class. Here is the constructor for DDATA:
ddata: method n: string m:string nv:num; fid = open(n, m); dname = n; mode = m; nvars = nv; endmethod;
where n is a parameter containing the name of the data set, m is the input mode, and nv is the number of variables.
This constructor method will be called when an example of the DDATA class is created using the _NEW_ operator. For example, the following code creates an example of the DDATA class representing the data set sasuser.x. The data set will be opened in input mode and has two variables.
init: dcl ddata d = _new_ ddata("sasuser.x", "i", 2); return;
Using the Data Set Class |
class ddata; /* Data */ public string dname; public string mode; protected num fid; protected num nvars; /* Constructor method */ ddata: method n: string m:string nv:num; fid = open(n, m); dname = n; mode = m; nvars = nv; endmethod; /* FETCH method */ read: method return=num; dcl num rc; rc = fetch(fid); return rc; endmethod; /* GETVARC method */ cpy: method n: num return=string; dcl string c = ""; if (vartype(fid, n) = 'C') then c = getvarc(fid, n); return c; endmethod; /* CLOSE method */ _term: method /(state='O'); if (fid) then close(fid); _super(); endmethod; endclass;
You can use this class as follows:
init: dcl ddata d = _new_ ddata("sasuser.x", "i", 2); dcl num more = ^d.read(); do while(more); dcl string s s2; s = d.cpy(1); s2 = d.cpy(2); put s s2; more = ^d.read(); end; d._term(); return;
In this example, the data set sasuser.x has two character variables, which you read and print until the end of the file is reached.
Now suppose that you create the following data set:
data sasuser.x; input city $1-14; length airport $10; if city='San Francisco' then airport='SFO'; else if city='Honolulu' then airport='HNL'; else if city='New York' then airport='JFK'; else if city='Miami' then airport='MIA'; cards; San Francisco Honolulu New York Miami ;
The output from the program will be
San Francisco SFO Honolulu HNL New York JFK Miami MIA
Copyright © 2009 by SAS Institute Inc., Cary, NC, USA. All rights reserved.