SAS Object-Oriented Programming Concepts |
You do not need to convert Version 6 classes to SAS Component Object Model (SCOM) classes in order to run programs from the previous versions. Version 6 classes are automatically loaded into SCOM formats when they are instantiated. Existing Version 6 SCL programs should run normally in Version 8 and beyond.
However, you can use the (SCOM) features that first appeared in Version 8 to make your programs more object-oriented, easier to maintain, and more efficient. Using SCOM features also enables you to reuse model classes in the future development of client/server applications.
To convert Version 6 model classes to SCOM classes, you must modify the method implementation files and regenerate the class files. To modify the method implementation files, follow these steps:
Remove global variables. Declare them as private attributes or, if they are referenced in only one method, declare them as local variables within that method. See Removing Global Variables for more information.
Declare all variables. See Declaring Variables for more information.
Convert labels to method names and convert LINK statements to method calls. Declare the labeled sections as private methods. If necessary, specify the Forward='Y' option for the method. See Converting Labels and LINK Statements for more information.
Convert CALL SEND statements to dot notation. See Converting CALL SEND to Dot Notation for more information.
Use CREATESCL to convert Version 6 class files to SCOM class files. See Converting Class Definitions with CREATESCL for more information.
Convert instance variables to attributes, if appropriate. See Using Instance Variables for more information.
Make sure signatures are generated for all methods. The best way to ensure that signatures are generated is to delete the method declarations from the class files and to replace them with the METHOD blocks from the method implementation files.
Change the class names specified in the CLASS statements if you do not want to overwrite the existing Version 6 classes.
Issue the SAVECLASS command to generate the new SCOM class.
Removing Global Variables |
Remove all global variables from the Version 6 method implementation entries. Convert them either to local variables through DECLARE or to private attributes in the class definition file. For example, suppose that a Version 6 method implementation file contains the variables N1, N2, C1 and C2 as shown:
length n1 n2 8; length c1 c2 $200;
In this example, four attributes need to be added to mylib.classes.newclass.scl, as follows:
Private num n1; Private num n2; Private char c1; Private char c2;
After the attributes are added, issue the SAVECLASS command to generate the new class.
Declaring Variables |
Declare all of the variables in your program. Lists should be declared with the LIST keyword rather than allowing them to default to a Numeric type. Objects should be declared either as generic objects (with the OBJECT keyword) or as specific class objects. You can use dot notation with an object only if it is declared as an object. Using specific LIST and object declarations can avoid problems with overloading methods. For more information, see Overloading and List, Object, and Numeric Types.
Whenever possible, classes should be declared with a specific class declaration such as
dcl work.a.listbox.class lboxobj;
Try to avoid using generic object declarations such as
dcl object lboxobj;
Also, the compiler cannot check method signatures or validate methods and attributes if it does not know the specific class type. If the compiler is not able to do this checking and validation at compile time, then SCL must do it at run time, which makes your program less efficient.
For example, assume that you declare a generic object named SomeC that has a method Get, which returns a numeric value. You also declare a class named XObj that has a method M, which is overloaded as (N)V and (C)V. Suppose you need to pass the return value of Get to the M method:
dcl object SomeC = _new_ someclass.class(); dcl work.a.xclass.class XObj = _new_ xclass.class(); XObj.M(SomeC.Get());
SomeC is declared as a generic object, so the compiler cannot determine what object it contains at compile time. Even though there is a specific object assignment to SomeC, the compiler cannot guarantee what type it will contain at any given point, because the value could be changed elsewhere when the program runs.
Therefore, the compiler cannot look up the Get method to find that it returns a Numeric value, and it cannot determine which method M in Xclass to call. This method validation must be deferred until run time, when the return type of the Get method will be known (because the actual call will have taken place and the value will have been returned).
The problem can be remedied by declaring SomeC as a specific object:
dcl someclass SomeC = _new_ someclass.class();
If this is not possible, then you could declare a Numeric variable to hold the result of the Get method, as shown in this example:
dcl object SomeC = _new_ someclass.class(); dcl xclass XObj = _new_ xclass.class(); dcl num n; n = SomeC.Get(); XObj.M(n);
Even though the compiler cannot validate the Get method for the SomeC class, it can validate the method name and parameter type for XObj.
Converting Labels and LINK Statements |
The next step is to remove all link labels from the Version 6 method implementation catalog entries. Convert them to private methods in the class definition file, and convert the link to a method call. For example, suppose that myclass.classes.old.scl contains the following:
m1: method; link a1; endmethod; a1: ...SCL statements... return;
To change the labeled section to a private method in mylib.classes.newclass.scl, add the following:
a1: Private method; ...SCL statements... endmethod;
If needed, you can also add parameters to the method. To change the link to a method call, change the following:
m1: method; a1(); endmethod;
In the old entry, the A1 labeled section is after the M1 method. In the new entry, the labeled section has been converted to a method. However, you cannot call a method before it is declared. To fix this problem, you must either move the A1 method before the M1 method, or you can declare A1 with the Forward='Y' option:
a1: Private method / (Forward='y'); ...SCL statements... endmethod;
Converting CALL SEND to Dot Notation |
The final step in modifying your method implementation files is converting CALL SEND statements to METHOD calls that use dot notation.
Note: To use dot notation, the method that you specify must have a signature. Therefore, you cannot convert CALL SEND statements to dot notation unless your class files have been converted to SCOM class files. Also, the object that you specify should be declared as a specific class type to enable the compiler to validate method parameters.
For example, suppose that a Version 6 program contains the following line:
call send(obj1,'m1',p1);
Converting this line to dot notation results in
obj1.m1(p1);
Converting Class Definitions with CREATESCL |
Assume that the Version 6 class is mylib.classes.oldclass.class and that the method implementation file is mylib.classes.old.scl.
Use CREATESCL to create an SCL entry that contains the following SCL statements:
Init: rc=createscl('mylib.classes.oldclass.class', 'mylib.classes.newclass.scl'); return;
Issue the SAVECLASS command to generate the Version 6 class file mylib.classes.newclass.class.
Open this entry in the Build window and modify the class definition as needed. Reissue the SAVECLASS command to generate the new class file in SCOM format.
Using Instance Variables |
The object model in Version 6 uses instance variables. In Version 8, instance variables were replaced with attributes.
When a class is loaded, the class loader automatically converts Version 6 formats to the SCOM format. This process includes converting instance variables to public or private attributes with the option IV, which specifies the name of the Version 6 instance variable.
In the following example, the Version 6 instance variable ABC is converted to the SCOM attribute abc.
class IVclass; public char abc / (iv='ABC'); endclass;
Copyright © 2009 by SAS Institute Inc., Cary, NC, USA. All rights reserved.