space
Previous Page | Next Page

Managing Methods

Implementing Methods with SCL

You can implement methods for your components with SCL code. The SCL implementation for a method can be stored in three different places:

When writing methods, keep the following tips in mind:

SCL and Overridden Methods

You can write methods to override existing methods, but you should execute the method on the parent class with the _super() routine. The _super() routine determines the current method context and then executes the method of the same name on the parent class. The point at which you execute the parent method can significantly affect the behavior of the overriding method. For example, if the _super() call occurs before any other statements in the METHOD section, the inherited behavior is executed before the overridden code executes. In order to use _super(), you must be inside a CLASS or USECLASS block.

Some methods require you to invoke the inherited method in a particular order. Each of the following examples is assumed to exist inside an appropriate CLASS or USECLASS block:

Note:   When overriding a method, you may not change its signature. If you require a different signature, you should overload the method.  [cautionend]


Using USECLASS Statement Blocks with Methods

By using USECLASS/ENDUSECLASS statements around an SCL method block, you can use methods and attributes for the specified class without repeating the class identifier. Due to compile-time binding, the SCL compiler can distinguish between local variables and class attributes. Refer to SAS Component Language: Reference for complete details on the USECLASS statement.

You can also use the _super() routine in the implementation of a method that is contained in a USECLASS statement block without having to specify the object identifier.

Note:   So that any new properties you have added are saved with a class, be sure to save a CLASS entry before compiling the SCL entry that contains its method implementation(s).  [cautionend]

If you override a method that has a signature of '(None)' and implement the method inside a USECLASS/ENDUSECLASS block, you must include a signature designation on the METHOD statement. For example, if you override the _foo method and _foo has a signature of '(None)', your SCL code could include

USECLASS mylib.mycat.myclass.class;
foo: method/(signature='N');
  /* ...insert additional code here... */
endmethod;
enduseclass;

Any method that is implemented within a USECLASS/ENDUSECLASS block must designate a signature.


Improving the Performance of SCL Code in Methods

Here are several tips to make the SCL code in your methods work more efficiently:

Be careful when you use recursion in methods.

You can use recursive calls such that a method can invoke itself. However, be sure to provide an exit case so that you do not recurse infinitely. Also be sure to invoke the inherited method with _super() and not with the form object.method(). Attempting to use a direct call to the method when you should use _super() results either in an infinite loop or in an out-of-memory condition.

Use the _term() method to delete objects.

If you programmatically create instances of objects in your SCL, you should always invoke the _term() method when your application no longer needs those objects. Objects that are no longer used are not automatically deleted while the application is running. Invoking the _term() method deletes the object and frees the memory that it occupies.

DCL sasuser.myclasses.myObj.class demoObj = _new_ myObj();
/* ...insert additional SCL statements here... */
demoObj._term();
  
Delete SCL lists that have been created by a method.

If any of your object's methods create new SCL lists, delete these lists with the DELLIST function. SCL lists take up memory and are not always automatically deleted. Leaving too many SCL lists open in memory can cause your application to run out of available memory.

Do not bypass SCL method-calling functions.

Always invoke the methods in the same manner, and do not bypass the method-calling functions that SCL provides. For example, consider a banking account class that has two methods, deposit() and update(). The deposit() method records a deposit, and the update() method updates a data set with the new account balance. You can implement these methods together in a single SCL entry, ACCOUNT.SCL:

   /* ACCOUNT.SCL: methods for the ACCOUNT class */
update: public method;
   /* ...SCL code to update a data set with the account information... */
endmethod;

deposit: public method
    amount:update:num;
    /* ...code to process a deposit goes here... */
endmethod;

Since you want to perform an update after each deposit, you may need to invoke the update operation from the DEPOSIT code. You may be tempted to call this operation directly, either with a LINK statement or by using CALL METHOD:

/* ACCOUNT.SCL: methods for the ACCOUNT class */
deposit: method 
         amount:update:num;
   /* ...code to process a deposit goes here... */

   /* this is the wrong way to do an update! */
   link update;
endmethod;
or
/* ACCOUNT.SCL: methods for the ACCOUNT class */
deposit: method 
         amount:update:num;
   /* ...code to process a deposit goes here... */

   /* this is also the wrong way to do an update! */
   call method('account.scl', 'update');
endmethod;

Both of these mechanisms may work when you first develop your application, but they violate basic principles of object-oriented programming. To understand why, consider what happens when someone decides to use your ACCOUNT class. They decide that your account class provides most of the functionality that they want, except that they want to record transactions in an audit trail. To do so, they override the update() method to also update the audit trail. If your deposit() method is implemented using either of the techniques presented above, then the new update() method is never called when a deposit is made.

The proper way to perform the update is to call the update() method:

/* NEW ACCOUNT.SCL: methods for the NEW ACCOUNT class */

USECLASS newaccount.class;
   deposit: method 
            amount 8;
   /* ...code to process a deposit goes here... */

      /* This is the correct way to do an update! */
      update();
   endmethod;
Then, if someone overrides the update() method, your deposit() method automatically invokes that new update() method. Of course, the developers of the new update() method that adds an audit trail should also invoke your original update() code using _super().
   update: method;
     _super();
     /* ...SCL code to update a data set */
     /* with the account information...  */
   endmethod;
ENDUSECLASS;

space
Previous Page | Next Page | Top of Page