Chapter Contents

Previous

Next
CLASS

CLASS



Creates a class using SCL code

Category: Object Oriented


Syntax
Details
Examples
Example 1: A CLASS Block with Method Implementation
Example 2: A CLASS Block without Method Implementation
Example 3: Definition of a Class
Example 4: Illustrating Short-Cut References
Example 5: Illustrating Set Custom Access(setCAM) Method
Example 6: Illustrating User-defined Events and Event Handlers
Example 7: Illustrating Forward Method, Optional= and ArgList=
See Also

Syntax

<ABSTRACT> CLASS class-name<EXTENDS parent-class-name>
<SUPPORTS supports-interface-clause>
<REQUIRES requires-interface-clause>
< / (class-optional-clause)>
<(attribute-statements)>
<(method-declaration-statements)>
<(method-implementation-blocks)>
<(event-declaration-statements)>
<(eventhandler-declaration-statements)>
ENDCLASS;

ABSTRACT
is an optional keyword used to define a class as an abstract class. Methods defined inside an abstract class are not required to have method implementations. Abstract classes are used to specify a common interface for several classes. An abstract class can not be instantiated through the _NEW_ operator.

class-name
is the name of a class that you are creating, which can be specified as a one- to four-level name.

parent-class-name
specifies the parent class of class-name and is specified as EXTENDS parent-class-name. Parent-class-name can be specified as a one- to four-level name.

If no EXTENDS clause is supplied, parent-class-name defaults to SASHELP.FSP.OBJECT.CLASS, which is the parent class of all SAS/AF classes.

supports-interface-clause
lists the interfaces that this class supports. Interfaces can be specified as follows:

SUPPORTSinterface-1<,interface-2...>

The interface names can be specified as one- to four-level names. All of the methods listed in SUPPORTS must be implemented in the CLASS block.

requires-interface-clause
lists the interfaces required for this class. Interfaces are specified as follows:

REQUIRES interface-1<,interface-2...>

The interface names can be specified as one- to four-level names. The REQUIRES interfaces are used for the client-server model. For more information, see INTERFACE.

class-optional-clause
specifies options for the class. Options should be placed inside parentheses following a / (slash). Separate multiple options with commas. Class options can be any of the following:

Description=description
is a description of the CLASS entry

MetaClass=class-name
is the four-level name of the CLASS entry that contains the model of a class. The default MetaClass is SASHELP.FSP.CLASS.CLASS.

attribute-statements
defines the class attributes, which determine how an object will look and behave. Attributes can either be scalars or arrays. The syntax of a class attribute statement is: access-scope type var-name< / (attribute options)>;

access-scope
can be one of the following:

`PUBLIC'
specifies that the attribute can be accessed by any SCL program. DECLARE may be used in place of public scope.

`PRIVATE'
specifies that the attribute can be accessed only from methods in the class where the attribute is defined.

`PROTECTED'
specifies that the attribute can be accessed only from methods in subclasses of the class where the attribute is defined. Since a class can be considered a subclass of itself, a protected attribute can also be accessed from the class where it is defined.

type
is the data type of the attribute. NUM, CHAR, LIST, OBJECT or a four-level class-name are possible values of type.

var-name
is the name of the attribute. You can specify a multi-dimensional array by providing an array dimension after var-name. For example:
PRIVATE num narray{3, 2, 3};

If an array variable has the same name as a method, the method name has higher precedence when referencing that array. To avoid ambiguity, use [ ] or { } instead of ( ) to specify the array reference.

attribute-options
specifies options for a class attribute. List options inside parentheses following a / (slash). Separate multiple options with commas. Attribute-options can be any of the following:

AutoCreate='N' | 'Y'
determines whether an SCL list is created automatically when an instance of the class is created. If AutoCreate='Y' (default), a four-level object name or SCL list is created depending on the attribute type. If 'N', then a four-level object name or SCL list is not created, and the user is responsible for creating and deleting this list.

Category=category-name
specifies the category for an attribute. Categories organize attributes so that you can display only attributes for the category. You can create your own category names. Components that are supplied with SAS software belong to the following categories:
Appearance
Data
Drag and drop
Help
Misc (Miscellaneous)
Region
Size/location
Misc is the default.

Description=attribute-description
specifies the description of the attribute. When you click on an attribute in the Class Editor, this text is displayed below the list of attributes.

Editable=`N' | 'Y'
determines whether attributes can be altered. 'Y' is the default.

If EDITABLE='Y', then the attribute can be set anywhere that it is in scope:

  • If the attribute is defined in class C and it is a public attribute, then it can be set anywhere.

  • If the attribute is defined in class C and it is a private attribute, then it can only be set from methods in the class C.

  • If the attribute is defined in class C and it is a protected attribute, then it can only be set from methods in C and subclasses of C.

If EDITABLE='N', then the ability to set the attribute is restricted based on its scope:

  • If the attribute is defined in a class C and it is a public attribute, then it can only be set from methods in C and subclasses of C.

  • If the attribute is defined in class C and it is a protected attribute, then it can only be set from methods in C.

  • If the attribute is defined in class C and it is a private attribute, it cannot be set anywhere. (It is effectively a constant.)

Editor=editor-entry-name
specifies a FRAME, SCL, or PROGRAM entry that returns a value. The Editor= option is available for attributes of all types except OBJECT. If supplied, the specified entry is displayed and executed by the Properties window when the ellipsis button (...) in the cell is clicked. The value that is returned from the entry is displayed in the cell in the Properties window.

Editors are typically FRAME entries that are designed to aid an application developer in specifying a value for an attribute. For example, for an attribute called 'textColor' that can be assigned to any hexcolor string, you could design a FRAME entry window to help the user visually see what the hexcolor string represents. The window could contain an RGB slider control with a sample box that shows the color that is being created as a user manipulates the red/green/blue sliders. In this example, you assign the name of the FRAME entry as the value of EDITOR=, and this window opens when a user selects the ... button for the TEXTCOLOR attribute in the Properties window.

GetCAM=method-name
specifies the custom access method to be executed when the value of the attribute is queried. Using dot notation to query an attribute for which a getCAM method has been defined may result in side effects. See What Happens When Attribute Values Are Set or Queried.

InitialValue=initial-values
specifies an initial value for the attribute. This option is valid only for attributes with types CHAR , NUM, and SCL LIST.For an example of using an SCL list as an initial value, see Initializing the Values in a List.

Linkable=`N' | 'Y'
determines whether an attribute is linkable from the Properties window. Only public attributes are linkable. Private and protected attributes are not displayed in the Properties window. Y is the default.

SendEvent=`N' | 'Y'
determines whether an attribute sends an event when modified. When SENDEVENT='Y', SAS assigns the Event Name, which has the format "attributeName Changed", and registers it with the component. Y is the default. When SENDEVENT='N', no Event name will be registered

SetCAM=method-name
specifies the custom access method to be executed when the attribute value is assigned.Using dot notation to set an attribute for which a setCAM method has been defined may result in side effects. See What Happens When Attribute Values Are Set or Queried.

State='N'|'O'
determines whether the attribute is new or is overridden. N is the default.

ValidValues=valid-values
specifies the values that are valid for the CHARACTER attribute. Use a space or '/' or ',' to separate the values.

The following options are used for compatibility with Version 6 classes:

Automatic=`Y' | 'N'
specifies whether var-name is an automatic instance variable.

IV=V6-instance-variable-name
specifies the name of a Version 6 instance variable.

PureIV=`Y' | 'N'
When PureIV='Y', it specifies that var-name is a pure Version 6 instance variable and that no associated Version 8 attribute will be created. N is the default.

method-declaration-statements
list the class methods.

For method-declaration-statements, use the following syntax:

method-label-name : <access-scope> METHOD<parameter-list>
< / (method-options)>;

method-label-name
can be up to 32 characters and has the same restrictions as an SCL label. By default, you should treat method-label-name the same as the method name. To define a more descriptive method name which is over 32 characters, use the method= option.

access-scope
can be one of the following:

PUBLIC
designates a method that can be inherited by subclasses and accessed anywhere the corresponding object exists. This is the default.

PRIVATE
designates a method that can be accessed only by methods in the class in which the method is defined. Private methods will not be inherited by subclasses of the class.

PROTECTED
designates a method that can be accessed only by subclasses in which the method is defined. Since a class can be considered a subclass of itself, a protected method can also be accessed from the class in which it is defined.

parameter-list
For parameter options such as using Input/Output/Update to store the parameter storage, using ":" operator to specify the parameter type, using Optional= to specify the varying arguments in the method, and using Return= to specify the method return type, as well as Arglist= and Rest=, can all be applied in the parameter list. For more information, see METHOD.

method-options
specify options for a class method. You must put the list inside parentheses that follow a / (slash). Separate multiple options with commas. The available options are

Abstract='N' | 'Y'
specifies that the method is an abstract method and does not have an implementation associated with it. Abstract methods can be declared only in abstract classes. The default is 'N'.

Description=method-description-string
specifies the description of the method.

Enabled=`N'|'Y'
determines whether a method can be temporarily disabled. Y is the default.

Label='method-label'
identifies a method whose label is different from the method-label-name. If the Label= option exists, the Method= option cannot be used.

Method='method-name'
identifies the method-label-name as the label name and the 'method-name' will be used for the method reference in the dot notation or CALL SEND routine. Since the 'method-name' is a string, you can extend the method name up to 256 characters. If the Method= option exists, the Label= option cannot be used.

Native='/executable-name:n
specifies the name of a system-implemented method.

Note:   This option is generated by the CREATESCL function.  [cautionend]

SCL | Entry=four-level-entry-name-string
identifies the entry that contains the USECLASS block that implements the method. This option is required when the method is not implemented in the SCL entry that contains the CLASS statement block.

Signature=`N'|'Y'
determines whether the method has a signature. Y is the default. All methods in Version 6 classes have Signature='N'. Adding parameter-list and removing Signature='N' for each method will cause the SCL compiler to generate signatures for that method. Signature='Y' is required for method overloading.

State=`O'|'N'
determines whether the method has been overridden or is new.

Forward='N'|'Y'
determines whether the method can be forward referenced when Forward='Y'. The SCL compiler is a one-pass compiler and will report errors when referencing a method that has not been defined in the current class. Using Forward='Y' will allow the SCL compiler to suppress the error messages and delay validation of the forward methods which are required to be defined later in the current class. If the forward method is not defined before the ENDCLASS statement, the SCL compiler will report the error. N is the default. This option can be used for methods calling each other.

ArgDesc1 | ArgDesc2 |...| ArgDescN =each-argument-description-string
specifies each argument description. This option is used for documenting the parameters.

ReturnDesc=return-argument-description-string
specifies the return argument description. This option is used for documenting the return parameter.

method-implementation-blocks
contain any SCL statements for the defined methods. These statements perform the operations of the method.

event-declaration-statements
define the class events. Declare the events as follows:

EVENT event-string-name < / (event-options)>;

event-string-name
is the name of the event you are declaring.

event-options
specifies options for the event. You must put the list inside parentheses that follow a / (slash). Separate multiple options with commas. Event options can be

Description=event-description
specifies the description of the event.

Enabled=`N'|'Y'
determines whether an event can be temporarily disabled. Y is the default.

Method=string
identifies the method that handles the event.

Send='Manual'|'After'|'Before'
determines when the object sends the event.

After is the default.

eventhandler-declaration-statements
define the event handler to be executed after the events are triggered. The event handler is an SCL method that handles the event. Declare the event handler as follows:
EVENTHANDLER eventhandler-name< / (eventhandler-options)>;

eventhandler-name
is the name of the event handler of an SCL class method that you are declaring.

eventhandler-options
specifies options for the event handler. You must put the list inside parentheses that follow a / (slash). Separate multiple options with commas. Event handler options can be

Description=eventhandler-description
specifies the description of the event handler.

Enabled=`N'|'Y'
determines whether an event handler can be temporarily disabled. Y is the default.

Event=event-name
specifies the name of the event.

Method=string
identifies the method that handles the event.

Sender='_SELF_' | '_ALL_'
identifies the location of the sender to trigger the event handler. When Sender='_SELF_', the event handler will only listen to events from the class itself. When Sender='_ALL_', the event handler will listen to events from any other class. Using the method _addEventHandler, you can dynamically add a sender to trigger the event.


Details

The CLASS statement enables you to use SCL to create a class and to define attributes, methods, events and event handlers for the class. The CLASS block is especially useful when you need to make many changes to an existing class such as adding signatures to an existing class, or when you want to create a class in batch mode. Using the CLASS block provides the advantages of error detection at compile time and improved performance during run time. It also enables you to use short-cut notation. Instead of using _SELF_.attribute or _self.method(...) to reference the name of a class attribute or a class method, you simply specify the attribute or method name. This makes programs easier to read and maintain. In addition, you can overload method definitions, which means that multiple methods can have the same name, but have different numbers and types of parameters.

The program block that defines a class starts with a CLASS statement and ends with an ENDCLASS statement. A CLASS block can contain statements that define attributes, methods, events, event handlers and even METHOD statement blocks implementing the operations for methods. You can also put the METHOD statements that implement class methods in another SCL entry when you use the SCL= method option to specify the name of that entry. Then, in the SCL entry that is specified with SCL=, define the methods for the class within a USECLASS statement block. Defining methods in a separate entry is useful for enabling class methods to be created, tested, or maintained by multiple application developers. For more information, see METHOD.

To create a class from an SCL entry that contains a CLASS block, you must compile and save the SCL entry as a CLASS entry. To do this, either issue the SAVECLASS command or select

File
[arrow]
Save Class
from the SCL Source Editor. This is equivalent to using the Class Editor to interactively create a CLASS entry. However, the Class Editor provides a graphical view of the class, whereas the CLASS statement in SCL provides a language view of the class.

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.

In methods that are defined in a CLASS statement block, all references to the methods and the attributes of the class can bypass two-level references to _SELF_.attribute and _SELF_.method(...). Because these methods are defined within the class, 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 inside a CLASS 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

_super.add();

To override the _init method, you must first call the super _init method before overriding the _init method. For example:

_super._init();
   ...statements that define the
   overridden _init method ...

Any SCL function or routine can be called inside a METHOD statement block that is inside a CLASS block. Outside the METHOD statement block, only class attribute statements, event statements and event handlers are allowed in a CLASS block. Other than the IMPORT statement, no SCL statements can be written outside the CLASS block.

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. This programming style will make your applications more consistent with the object-oriented paradigm.

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. It is probably best to avoid using the same name for multiple local variables, class attributes, method names or arrays to avoid problems.

The CLASS statement also enables you to define method definitions for overloading methods, which means that multiple methods have the same name. Methods that have the same names are allowed in a CLASS block only if the signatures, or parameter numbers or types, are different. For example, a class can have one COMBINE method that has numeric parameters and adds parameter values, and another COMBINE method that has character parameters and concatenates parameter values.

Inheritance from multiple classes is not supported in class syntax, but is allowed with interface syntax. For more information, see INTERFACE.


Examples

Example 1: A CLASS Block with Method Implementation

This example defines the Arith class, a subclass of Sashelp.Fsp.Object.class, and implements the methods in the CLASS entry. The example shows the METHOD statements using the RETURN= option and then RETURN statements returning values to the caller.

class work.classes.arith.class;
    public  num  total;
    public  char catstr;
        /* A method that adds numeric values */
    add:  public method n1:num n2:num return=num;
        total = n1 + n2;
        return (total);
    endmethod;
        /* A method that concatenates */
        /* character values           */
    concat: public method c1:char  c2:char return=char;
         catstr = c1 || c2;
         return (catstr);
    endmethod;
endclass;

Example 2: A CLASS Block without Method Implementation

This example defines the Combine class and specifies the SCL entry in which the methods are implemented. The class uses overloaded COMBINE methods, one to process numeric values and another to process character values. The code that implements the methods is defined in a USECLASS block.

class work.classes.combine.class;
    public  num  total;
    public  char catstr;

    combine: public method n1:num  n2:num  return=num
       / (scl='work.classes.combine.scl');

    combine:  public method c1:char c2:char
       return=char
       / (scl='work.classes.combine.scl');
endclass;

Here is the USECLASS block that contains the method implementations for WORK.CLASSES.COMBINE.CLASS:

useclass work.classes.combine.class;
   combine:  public method
         n1:num  n2:num  return=num;
      total = n1 + n2;
      return (total);
   endmethod;

   combine: public method
           c1:char  c2:char return=char;
      catstr = c1 || c2;
      return (catstr);
   endmethod;
enduseclass;    

Example 3: Definition of a Class

This example imports the Collection class, which is provided with SAS/AF software, and shows several forms of attribute declarations, method declarations, and overloading methods. Attributes list1 and list2, which define SCL list initialization, can also be found in this example.

import sashelp.fsp.collection.class;
class work.classes.myclass.class
    extends sashelp.fsp.object.class
    / (description = 'my first class file');
       /* simple attribute with no options */
    public num num1;
       /* Attribute with options */
    public num num2
       / (description = 'second numeric attribute',
          initialvalue= 3,
          validvalues = '1 2 3');
       /* Another attribute with options */
    public char string1
       / (editable = 'n', linkable = 'n',
         initialvalue = 'abc');

 /* SCL List initializations:items without name*/
    public list list1 
 / (InitialValue={1, 2, 3, 'abc', 'def', 4, 5, 6}
   ); 

 /* SCL List initializations:Items with name.*/
 /* Address is a sublist of list2          */
    public list list2
 / (InitialValue={name='John Doe', Number=100,
    Address={State='NC', CITY='CARY'},
    Office='Bldg Z'} )
    /* Private array attribute  */
    private num arr(3) ;
       /* Private list attribute   */
    private list list;
       /* Protected collection attribute */
    protected collection coll;

       /* public method m0 */
   m0:  Public method
            /* External method implementations */
       / (scl='mylib.classes.b.scl',
         label = 'M0',
         description='test method m0');

       /* Public method m1        */
       /* with no method options  */
   m1:  public method ;
      ...more SAS statements...
   endmethod;

      /* Private overloading method m1 */
      /* with numeric parameter        */
   m1:  private method n: num;
      ...more SAS statements...
   endmethod;

      /* Protected overloaded method m1.
       * Method implementations should be placed in 
       * work.classes.c.scl */
   m1:  protected method s: char
     /* external method implementation */
      / (scl = 'work.classes.c.scl');

      /* Other public method */
   m2: method return=num;
      ...more SAS statements...
      return (1);
   endmethod;

       /* Private method */
   m3: private method;
      ...more SAS statements...
   endmethod;
endclass;

Example 4: Illustrating Short-Cut References

This example shows how to use the _super method as well as short-cut references to _SELF_:

CLASS work.classes.another.class;
    Public Num n1;
    Public Num n2;
    Public Char c1;
    Public Char c2;
    Public Num m(3);

    _Init:  method / (State='O');
        DCL Num  n2;
        DCL Char c2;
            /* Equivalent to call super(_init); */
        _SUPER();
           /* Equivalent to _SELF_.N1 = 1   */
        n1 = 1;
           /* Local variable N2 dominates class */
           /* attribute N2                     */
        n2 = 1;
        m{1} = abs(n2);
           /* Uses { to avoid ambiguity    */
           /* Equivalent to _SELF_.C1 = 'a' */
        c1 = 'a';
           /* Local variable C2 dominates */
           /* class attribute C2          */
        c2 = 'a';
     endmethod;
        /* commonly used method can be PRIVATE */
     Common: Private Method a:Num;
        ...more SCL statements...
        a = a + 1; 
     endmethod;

     M: method;
          /* Equivalent to             */
          /*    if _SELF_.N1 > 0 then  */
       if n1 > 0 then
             /* Equivalent to      */
             /*     _SELF_.N1 + 1; */
          n1 + 1;
       common(n1);
     endmethod;
           /* Method M1 with numeric parameter */
     M: method n: Num;
           /* Equivalent to _SELF_.M(); */
        M();
        common(n1);
     endmethod;

endclass;

Example 5: Illustrating Set Custom Access(setCAM) Method

This example shows a setCAM method, M1, which will be invoked when the attribute N is modified in the _init method.

Class work.mycat.camDemo.class;
    Public num n / (initialValue = 5, 
                    setCam='m1');
    _init: Method / (State='O');
           _super();
           n = 3;
           EndMethod;
    m1:    Method nParm:Num;
     /* - nParm is input value of attribute n */
           nParm = nParm + 100;
     /*  nParm is output value of attribute n */
           EndMethod;
EndClass;          

To reference the camDemo class, you can code the following program:

Init:
    DCL  camDemo  obj = _new_ camDemo();
    obj.n = 7;
    /*   Using the SCL debugger to trace the sequence   
     *   of this program, you will find the value          
     *   of obj.n = 107 */
    put obj.n=;
    Return;

Example 6: Illustrating User-defined Events and Event Handlers

This example shows a system-defined event, 'n Changed', which will be automatically generated to associate with the attribute N. An event handler, M1, which is associated with the 'n Changed' event is also written and will be executed when the attribute N is modified. Another user-defined event, 'myEvent', is created by the EVENT statement. The associated event handler, M2, will be executed when an explicit _sendEvent method is executed.

Class work.mycat.eDemo.class;
     Public num n; /* sendEvent='Y' is default*/ 
     Public char c / (sendEvent='N');
     Event 'myEvent' 
        / (method='m2');
     EventHandler m1 
        / (Sender='_SELF_',
           Event='n Changed');
     EventHandler m2
        / (Sender='_ALL_',
           Event='myEvent');
     m1: method a:list;
       Put 'Event is triggered by attribute N';
         endMethod;
     m2: method a:string b:num ;
       Put 'Event is triggered by _sendEvent';
         return (100);
         endMethod;
EndClass;

You could use the following program to trace the control sequence of the event handler by using the SCL debugger.

 init:
    DCL eDemo obj = _new_ eDemo();
    obj.n = 3;  /* will trigger the m1 */
    obj._sendEvent('myEvent','abc',3);
    Return; 
 

Example 7: Illustrating Forward Method, Optional= and ArgList=

This example shows how to use the method option Forward='Y' to write a method, M1, which can invoke another method, M2, defined after the current method, M1. Without the Forward='Y' option, the SCL compiler will issue an error. The M1 method contains Optional=, which actually includes two overloading methods.

Class mylib.mycat.forward.class;
   m2: Method n:num c:char Return=Num / (Forward='Y');
   m1: Method n1:num Optional=n2:num Arglist=argList 
Return=Num;
          DCL Num listLen = listlen(argList);
          DCL Num retVal;
          if (listLen = 1) then
             retVal = m2(n1, 'abc');
          else if (listLen = 2) then
             retVal = m2(n2, 'abc');
          Return(retVal);
       EndMEthod;
   m2: Method n:num c:char  Return=Num;
          Return(n+length(c));
       EndMethod;      
EndClass;   

See Also

ARRAY

CREATESCL

ENDCLASS

METHOD

USECLASS


Chapter Contents

Previous

Next

Top of Page

Copyright 1999 by SAS Institute Inc., Cary, NC, USA. All rights reserved.