|Example 1: Group Development Using a USECLASS Block|
|Example 2: Valid SCL Statements in a USECLASS Block|
|Example 3: Bypassing _SELF_ References in a USECLASS Block|
|Example 4: Subclassing TextEntry_c for FRAME Programming|
The USECLASS statement binds methods that are implemented within it to a class definition. USECLASS blocks are especially useful for defining method implementations in a separate SCL entry from the one that contains the CLASS statement that defines the class. This feature enables group development of classes, because multiple people can work on class methods implementations simultaneously.
USECLASS labels the beginning of a program block that implements methods for class-name. The USECLASS statement block ends with the ENDUSECLASS statement. Class-name must be already defined in an existing CLASS entry.
The only SCL statements allowed in USECLASS blocks are METHOD implementation blocks. The signature (parameter types) of methods must match the associated method definitions in the CLASS entry. If a return type is defined, it must also match the associated method definition in the CLASS entry. If the parameter storage (INPUT/OUTPUT/UPDATE) is omitted, the SCL compiler will assume that it has the same storage specification as the associated method definition in the CLASS entry.
Method implementations inside a USECLASS block can include any SCL statements (except CLASS, USECLASS, or INTERFACE statements), or SCL functions and routines, including DECLARE to declare local variables. If you want to define a local variable that can be used across the class, you must define it as a private attribute either inside the CLASS statement or in the Class Editor. METHOD blocks can include labeled sections. However, labeled sections that are outside a method block must be re-coded as PRIVATE methods, and the LINK statements that call them must be changed to method calls. For more information, see METHOD.
If a local variable that is defined in a METHOD block has the same name as a class attribute, SCL gives precedence to the local variable. If a class method has the same name as any SCL-supported function, SCL gives precedence to the function. If an attribute array has the same name as a class method, SCL gives precedence to the method.
Do not declare the _SELF_, _FRAME_, _CFRAME_, _METHOD_, or _EVENT_ system variables inside a CLASS or USECLASS block. SCL automatically sets these values when it is running methods that are defined in CLASS or USECLASS blocks. Redefining any of these system variables can introduce unexpected behavior.
Because USECLASS binds the methods that it contains to the class that is defined in a CLASS entry, all references to the methods and the attributes of the class can bypass references to _SELF_.attribute and _SELF_.method(...). Because the binding occurs at compile time, the SCL compiler can detect whether an undefined variable is a local variable or a class attribute.
You can also use the _super method in method code that is inside a USECLASS statement block without having to specify either an object identifier or the method whose super method you are calling. You can use the _super method to call any method. For example, to invoke the super ADD method, you would use
To override the _init method, you must first call the super _init method. The _init method can be short-cut. For example:
The USECLASS statement also enables you to define implementations for overloading methods, which means that multiple methods have the same name. Methods that have the same name are allowed in a USECLASS block only if the signatures, or parameter numbers or types, are different. For example, a class can have a COMBINE method that has numeric parameters and that adds parameter values. It can also contain another COMBINE method that has character parameters and that concatenates parameter values.
USECLASS can be used for group development. Suppose a group with three members ONE, TWO and THREE was assigned to develop WORK.A.GROUP.CLASS. This class is defined as follows:
Class work.a.group.class; Public Num nAttr; Public Char cAttr; m1: Method n:Num / (scl='work.a.one.scl'); m1: Method c:Char / (scl='work.a.one.scl'); m2: Method n:num / (scl='work.a.two.scl'); m3: Method Return=Num / (scl='work.a.two.scl'); m4: Method Return=Char / (scl='work.a.three.scl'); EndClass;
Issue the SAVECLASS command to create this class. After the class is created, programmer ONE starts to create method implementations in WORK.A.ONE.SCL as follows:
UseClass work.a.group.class; m1: Method m:Num; nAttr = m; EndMethod; m1: Method c:Char; cAttr = c; EndMethod; EndUseClass; +
Programmer ONE is also responsible for compiling and testing this method implementation before the final system integrations.
Programmer TWO creates method implementations in WORK.A.TWO.SCL as follows:
UseClass work.a.group.class; m2: Method n:Num; put n=; EndMethod; m3: Method Return=Num; return(nAttr); EndMethod; EndUseClass;
Programmer TWO is also responsible for compiling and testing this method implementation before the final system integrations.
Programmer THREE creates method implementations in WORK.A.THREE.SCL as follows:
UseClass work.a.group.class; m4: Method return=Char; Return(cAttr); EndMethod; EndUseClass;
Programmer THREE is also responsible for compiling and
testing this method implementation before the final system integrations. From
this example, we found that a USECLASS block can be used to simplify group
development in an object-oriented development environment.
This example shows that a method implementation block is the only SCL statement allowed in a USECLASS block. Other SCL statements such as the DECLARE statement are not allowed in a USECLASS block. However, these SCL statements can be written inside the method implementation block.
USECLASS work.classes.myclass.class; /* Method M1 without a signature */ M1: method; ...more SCL statements... endmethod; /* The next statements are invalid because */ /* they are not in a METHOD statement. They */ /* will produce a compiler warning message. */ DCL num n = 1; /* Invalid statement */ n=10; /* Invalid statement */ /* Method M1 has a numeric parameter. */ M1: method n: num; /* Any SCL statement can be applied in the */ /* method implementation block. */ DCL num n; n = n + 1; ...more SCL statements... endmethod; /* Method M1 has a character parameter. */ M1: method s: char; DCL Char arr(3); DCL num i; DO i = 1 to dim(arr); arr(i) = s; END; ...more SCL statements... endmethod; /* The next statement is invalid because */ /* it is not in a METHOD statement. */ if s=1 then put 'pass'; /* Other methods */ M2: method return=num; ...more SCL statements... return(1); endmethod; ENDUSECLASS;
Assume that there are four class attributes defined for a class: N1 and N2 are numeric attributes, and C1 and C2 are character string attributes. Both M1 methods are class methods. One of the M1 methods takes no parameter. The other M1 method takes one numeric parameter. The private method M2 is used as a debugging routine. If the variables or methods are class attributes or class methods, short-cut syntax (see also Referencing Class Methods or Attributes) can be used to bypass dot notation.
Import Sashelp.Fsp.Colleciton.Class; Useclass work.classes.another.class; _init: method / (State='O'); /* Equivalent of _super._init(); */ /* or call super(_self_,'_init'); */ _super(); /* Equivalent to _self_.n1=1 */ n1=1; /* Local variable n2 dominates */ /* class attribute n2 */ n2=1; /* Use SAS function ABS */ n3(1)=abs(n2); /* Equivalent to _self_.c1='a' */ c1='a'; /* Local variable c2 dominates */ /* class attribute c2 */ c2='a'; endmethod; m1: method; /* Equivalent to if _self_.n1>0 then */ if n1>0 then /* Equivalent to _self_.n1 + 1 */ n1+1; else /* Equivalent to */ /* _self_.m1(_self_.n1); */ m1(n1); endmethod; /* Method m1 with numeric parameter */ m1: method n: num; if (n < 0) then n = --n; /* - Invoke M1 method -- */ m1(n); m2(n+n); DCL Collection col = _NEW_ Collection(); /* - Must use the dot notation here - */ col.add(3); endMethod; /* - Private Debugging method -- */ m2: Private Method n:Num; put 'Debugging ' n=; endMethod; endUseClass;
The class Mywidget is defined using SCL class syntax. First, edit WORK.A.MYWIDGET.SCL and include the following source:
Import Sashelp.Classes; Class work.a.Mywidget.class Extends textEntry_c; m1: Public Method c: char / (scl='work.a.myClass.scl'); EndClass;Issue the SAVECLASS command to compile this program and create the CLASS entry WORK.A.MYWIDGET.CLASS.
Edit WORK.A.MYCLASS.SCL, using USECLASS to include the method implementations.
Useclass work.a.Mywidget.class; m1: Method c:char; text = c; /* Equivalent to _SELF_.text = c; */ /* Text is an class attribute */ EndMethod; EndUseClass;
Compile this program.
Now edit WORK.A.B.FRAME, and in the component window add the Mywidget class to the list (via the AddClasses button on the pop-up menu). Drag the Mywidget class to the frame and in the frame's SCL source, enter
Init: Mywidget1.m1('Hello! '); Return; Main; Return;Compile and TESTAF this program. You should see Mywidget with "Hello!" in the text field. This example could also be done using only the CLASS block (without USECLASS). Just put the method implementation directly in the CLASS block.
Import Sashelp.Classes; Class Mywidget Extends TextEntry_C; m1: Method c:Char; Text = c; EndMethod; EndClass;
Top of Page
Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.