Tutorial

Using aJS_DbC

aJS_DbC ('AspectJS Design by Contract') is a stand-alone function that is an optional adjunct to the AJS object. Calling aJS_DbC causes rigorous checking subsequently of the type, number and value of arguments passed to all calls to AJS methods, and the methods of the Affix objects that they generate. An improper call to these methods raises an exception, wherein the Error object generated contains a detailed description of the problem, thus expediting its resolution.

aJS_DbC is a recursive application of the AJS object in that it uses the object to apply affixes to its own methods. This allows argument-checking code to reside externally to the core technology, thus permitting its effect to be enabled and disabled trivially, and thus giving equally trivial control over the overheads it incurs. Programmers can thereby enjoy all of the benefits of a design-by-contract approach during development, yet avoid all of its costs when the system is deployed.

aJS_DbC is very easy to use, and to eschew its benefits is to invite long periods of frustration while you attempt to trace an errant method-call. You are therefore advised strongly to use aJS_DbC when developing any system that uses the AJS object.

Using aJS_DbC

To use aJS_DbC, import the code that defines the function into the application first. Then call it just once, as soon as possible in the application's run, passing a reference to the AJS object. No other action is needed following that, and the application can continue thereon to make entirely normal calls to AspectJS methods.

Example 63 illustrates this.

To discontinue using aJS_DbC you should disable the import directive, and comment out or delete the call to the function.


 <!-- Example 63 -->

 <html>
    <head>
       <script type = "text/javascript" src = "AJS.js"></script>
       <script type = "text/javascript" src = "aJS_DbC.js"></script>
       <script type = "text/javascript">

       aJS_DbC (AJS);

       // Other code, including normal calls
       // to AspectJS methods occur hereon

       </script>

    </head>

    <body> ...  </body>

 </html>
            

Argument Checking in Action

Following a call to aJS_DbC, any call to an AspectJS method that contains a bad or missing parameter generates an exception. This includes methods of the AJS object, Affix objects and the methods that interceptees acquire by dint of being intercepted.

Example 64 demonstrates the idea by making a call to AJS.addPrefix with the intent of intercepting calls to myFunc such that myPrefix executes first. However, the call to addPrefix omits the quotes around the second argument (deliberately), which constitutes an error.

However, aJS_DbC's prior invocation causes detection of the missing quotes, therefore an an Error object is thrown, the message member of which contains a detailed report on the nature of the problem, as the example shows.

Note that the full set of exception conditions is covered comprehensively and completely in the API Documentation.


 // Example 64

 function myFunc   () { }
 function myPrefix () { }

 aJS_DbC (AJS);

 try
    {
    AJS.addPrefix (this, muFunc, myPrefix);
    }

 catch (E)
    {
    alert (E.message);
    }

 --------------------------------------

 Output:

 Error in call to AJS.addPrefix - 'muFunc' is not a member
 of the IOwner specified. Client-code call point: undefined
            

Signature Augmentation

Calling aJS_DbC augments the calling signature of all but a few AspectJS methods with a single trailing-parameter called 'CallPoint'. This is an optional argument that is intended to be of use in debugging, and whose value is incorporated into the contents of the message member of the Error-objects that are thrown when bad calls are detected.

It is at its most useful when it is a string that indicates the context of a call, and can, for example, contain filename and line-number information. This principle can be extended to include, for example again, time and date information. If unused, exception-message strings generated by bad calls state that the call point is undefined (as is the case in Example 64).

Note that the trailing nature of the CallPoint argument means that using it mandates provision of values for preceding arguments that are otherwise optional. In this case, and if these arguments are of no interest, then the caller must provide default or safe values for them.

Note also that the CallPoint argument is used only by the checking mechanism that aJS_DbC puts in place, therefore it has no effect on any AspectJS method. Given this, it is therefore safe, if a little inefficient, to leave any CallPoint arguments in place when deploying an application with aJS_DbC disabled.

Example 65 demonstrates these points by calling AJS.addPrefix and attempting to pass a negative value for the Execs argument.


 // Example 65

 function myFunc     () {  }
 function prefixFunc () {  }

 aJS_DbC (AJS);

 try
    {
    AJS.addPrefix (this, "myFunc", prefixFunc, undefined, -1, "Example 65, Line 12");
    }

 catch (E)
    {
    alert (E.message);
    }

 --------------------------------------

 Output:

 Error in call to AJS.addPrefix - Execs argument has a value of less than 1.
 Client-code call point: Example 65, Line 16
            

Detecting Redundant Affix-Object Calls

aJS_DbC also accepts an optional reference to a user-defined call-back function, which is invoked whenever a call is made to a method of an Affix object that has been detached from its interceptee.

Detatched Affixes that remain unrecovered by the garbage collector are useless from the point of view of AspectJS, and consume resources redundantly, unless the application has its own reasons for keeping them. Given this, aJS_DbC helps considerably in eliminating such inefficiencies, as the call-back function can report calls to redundant objects to the developer.

Example 66 demonstrates using the onRedundantCall argument.


 // Example 66

 function myFunc          () { }
 function myPrefix        () { }

 function onRedundantCall (Message)
    {
    alert (Message);
    }

 aJS_DbC (AJS, onRedundantCall);

 var MyPrefixObj = AJS.addPrefix (this, myFunc, myPrefix);

 MyPrefixObj.remove   ();
 MyPrefixObj.setExecs (10);

 --------------------------------------

 Output:

 Redundant call made to setExecs method of
 an AspectJS Prefix object. Client-code call
 point: undefined
            

Calling aJS_DbC Redundantly

Note that calling aJS_DbC more than once is redundant. To do so would simply add another set of affixes to the relevant functions, yet in the event of a bad call to any of those methods, the first function in the prefix-set would be the only one to trap the error.

Moreover, in the event of good calls to a given method (which, after all, is the modal case), multiple-DbC affixes would simply repeat the argument-checks redundantly, and would perpetuate the application of multiple DbC-affixes to any Affix objects generated. This would constitute nothing more than a drain on resources.

Given this, aJS_DbC will generate an exception if invoked multiple times. Moreover, it also accepts its own CallPoint argument, to aid in tracking down such offending invocations (in the seemingly unlikely event that such assistance is needed).

Example 67 demonstrates these two points.


 // Example 67

 try
    {
    aJS_DbC (AJS, null, "Point A");

    // ...

    aJS_DbC (AJS, null, "Point B");

    }

 catch (E) { alert (E.message); }

 --------------------------------------

 Output:

 Warning: Repeated call made to aJS_DbC - multiple calls
 to this function are disallowed because they would be
 redundant and would impinge on performance subsequently.
 Client-code call point: Point B
            

Go forward to Part 9 of this tutorial.
Go back to Part 7 of this tutorial.