Previous | Next | |
9.5.5 Augmenting Class definitions with Metadata
ActionScript 2.0 is an object-oriented language with many of the capabilities familiar to users of other object-oriented languages such as Java or C++. KineticFusion used the definitions of AS2.0 classes and class members in order to carry out semantic analysis of embedded and external ActionScript. While there is sufficient information available in these definitions for many high-level object-oriented languages, there are several drawbacks when checking AS2.0 scripts:
- In AS2.0, it is common to have several possible method signatures for a method or function, however only a single signature can be specified in the class file
- There is no mechanism for declaring constants that can be inlined
- There is no mechanism for restricting the extension of a class or class member
- There is no mechanism for providing a specification for an abstract method that must be overridden by a sub-class.
KineticFusion 3.0 allows developers to add new compile-time constraints to ActionScript classes without affecting the behavior of these classes in any other ActionScript compiler. These constraints are specified within Javadoc comments that can be defined for each class/interface member and for the overall class or interface. This is a mechanism familiar to developers used to working with Enterprise Javabeans or other automated class generation tools. Because these constraints are specified only in comments, the constraints are transparent to all other compilers.
9.5.5.1 What is a Javadoc comment?
Javadoc comments were first introduced in the Java programming language to define documentation that can be automatically generated from class files. Since then, the approach has spread to many different programming languages and the usage now extends beyond documentation. First let's look at a few examples of Javadoc comments:
/** * This is a simple comment */ /** This is a comment on one line */ /** All those asterisks are optional - just makes comments easier to read but they're removed automatically */ /** @author Eddie Spaghetti */ /** * @author Eddie * Spaghetti */ /** * This method adds one or more <code>String</code>s or <code>Number</code>s * to a list * @signature String[256] * @signature Number[256] */
A Javadoc comment always starts with '/**' and ends with '*/'. It is different from a standard multi-line comment only in that there are two asterisk characters after the opening slash. All whitespace and asterisks at the beginning of a line are ignored. The contents of the comment are as follows:
- An optional text comment that can be spread over multiple lines. This text is normally HTML as it can then be used to create automatic HTML documentation with the appropriate documentation generator.
- A tag block. A tag block is made up of zero or more lines defining Javadoc tags. Each tag must occur at the beginning of a line and is identified by an '@' character followed by a name e.g. @author, @method. Each tag can be followed by arbitrary text that can span multiple lines.
KineticFusion will automatically examine all Javadoc comments within ActionScript class files provided these comments are immediately preceding the class declaration or class member declaration that they are describing. The following is valid:
/** * This method adds an item * @final */ public function add( obj:Object):Void { this._add(obj); }
However the Javadoc constraints defined in the next example will not be seen since they are not defined directly before the class member:
/** * This method adds an item * @final */ [Inspectable(defaultValue="")] public function add( obj:Object):Void { this._add(obj); }
There is extensive information on the Javadoc specification at http://java.sun.com/j2se/javadoc
9.5.5.2 Supported KineticFusion Tags
Tag names used by KineticFusion are case-insensitive. The following metadata tags are supported:
- @abstract
- @final
- @const
- @signature
- @mixin
As more constraints are required by users over time, the set of supported tags will also grow.
9.5.5.2.1 The Abstract tag
An abstract object is an object that must be overridden to be used. In ActionScript only classes and class methods can be marked as abstract. Classes and methods cannot be tagged as both Abstract and Final. Any additional text on the Abstract tag is ignored.
9.5.5.2.1.1 Abstract Classes
When a class is tagged as Abstract, it cannot be instantiated by any other class. Abstract classes are normally classes that are incomplete and designed only to be subclassed. KineticFusion will automatically signal an error when it detects code that attempts to instantiate an abstract class. All classes that contain abstract methods must also be marked as abstract since the implementation of any abstract methods are not available. For example:
/** * This is an abstract shape class * @abstract */ public class Shape{ private var myBounds: Rect; public getPoints():Rect { return myBounds; } /** * This method must be implemented by the concrete shape subclass * @abstract */ public function draw() { return null; } }
9.5.5.2.1.2 Abstract Methods
An abstract method is a method whose implementation is to be provided by a subclass. Abstract methods must have a single statement in their body to ensure that the classes compile with all other compilers: for Void methods, this statement must be a simple 'return' statement; all other return types must have a single 'return null' statement. If any other statement is found, KineticFusion will automatically signal an error.
KineticFusion will automatically remove the empty method body when it writes out the class to the SWF. Since an abstract method does not have an implementation, the class must also be tagged as abstract to prevent it being instantiated. If the class is not tagged as abstract, KineticFusion will signal an error. A subclass of a class that contains an abstract method must provide an implementation of the method. If an implementation is not provided the subclass must also be tagged as abstract otherwise KineticFusion will signal an error.
9.5.5.2.2 The Final tag
A final object is an object that can never be overridden. The final tag can be applied to classes, fields, methods and properties. Classes and methods cannot be tagged as both Abstract and Final. Any additional text on the Final tag is ignored. For example, the intrinsic Camera class should not be allowed to be extended as there is no public constructor. To prevent this, it can be marked final:
/** * Camera Class * @final // Because instances cannot be created programmatically */ intrinsic class Camera{ ...
9.5.5.2.2.1 Final Classes
Final classes cannot be extended by a subclass. KineticFusion will signal an error if class attempts to subclass an Final class.
9.5.5.2.2.2 Final Fields
Final fields cannot be overridden in a subclass. KineticFusion will signal an error if sub class attempts to redefine a final field.
9.5.5.2.2.3 Final Methods
Final methods cannot be overridden in a subclass. KineticFusion will signal an error if sub class attempts to redefine a final method.
9.5.5.2.2.4 Final Properties
Final properties cannot be overridden in a subclass. KineticFusion will signal an error if sub class attempts to redefine a final property. The Final tag is applied to both the getter and setter property methods, even when specified on a single method.
9.5.5.2.3 The Const Tag
The const tag is only applicable to fields and defines a field that is initialized with a constant value that can be inlined whenever it is referenced. Any additional text on the Const tag is ignored. For example:
/** * Define global rotate constants * @const */ var SIN_45:Number = Math.sin(45), COS_45:Number = Math.cos(45);
9.5.5.2.3.1 Constant Fields
If a field is tagged as Const but does not define a constant initialization value then KineticFusion will signal an error. Constant expressions and Math library expressions are permitted provided their actual values can be resolved at compile-time.
9.5.5.2.4 The Signature Tag
KineticFusion provides powerful type-checking features when checking method calls. As ActionScript does not support method overloading, however, methods frequently permit different argument types. Rather than reduce the type-checking features by making parameter types generic, the Signature tag permits a developer to explicitly specify all acceptable method signatures. For example, the sort() method of the intrinsic Array class can have four different parameter signatures:
/** * First argument can be a compare function, or a numeric options constant. * When a compare function is specified, an options argument can be specified as * an additional argument * @signature * @signature compareFn:Function * @signature compareFn:Function, options:Number */ public function sort( options:Number):Object;
The Signature tag is only applicable for methods. The tag text is significant and is interpreted as follows:
If there is no text then the tag indicates that an empty argument list is acceptable
If text is defined, it represents a comma-separated list of typed identifiers that represent the optional method signature. As the field names are not used inside the method body these are optional however it is recommended to include them for clarity purposes e.g. The following two declarations are treated the same:
/** * @signature compareFn:Function */
And:
/** * @signature :Function */
The identifier can be omitted but the colon character and the type is always required. The Signature tag also permits the specification of the maximum number of times a specified parameter can occur without enumerating each signature element explicitly. This is accomplished by adding a maximum cardinality after a type surrounded by square brackets ( '[' and ']'). For example, the concat() method of an array can take no arguments, an Array argument, or an arbitrary number of Object arguments. The signature for this method would look like:
/** * Also support multiple parameters * @signature * @signature data:Object[256] */ public function concat( array:Array):Array;
The minimum cardinality is always one.
KineticFusion will always attempt to find a matching signature for every set of method arguments. Only when all possible matching combinations are exhausted will the application signal a Warning that the method arguments are incorrect.
9.5.5.2.5 The Mixin Tag
In ActionScript, it is possible for classes to get new behaviors dynamically during execution. In some programming languages it is possible for a class to extend multiple classes and so inherit multiple behaviors. Instead, in ActionScript, new methods can be added to classes at run-time to provide additional behaviors that are normally independent of the rest of the class's behaviors - that is, new independent behaviors are 'mixed-in' with the existing class behaviors. A common example of this is where a class wishes to implement an event dispatching behavior so listeners can be registered for events generated by an object:
function addEventListener(event:String, handler:EventHandlerType):Void; function removeEventListener(event:String, handler:EventHandlerType):Void;
As this is generic functionality, it does not make sense to define the code within every class. Instead, the functionality is added to the class at runtime. Because of this, they cannot be defined inside the class source file. Instead, field place holders are used, and these fields can be referenced by classes wishing to use the functionality:
public var addEventListener:Function; public var removeEventListener:Function;
However, this means that the signatures for the methods are no longer available to be checked by the compiler. The Mixin tag is used to define the class and method that corresponds to a specific class field of type Function. All signatures of the specified method are added to the field so that full type checking can occur. The Mixin tag is only applicable for class fields - the text of the tag specifies the name of the class that contains the method followed by the method name, separated by a '#' symbol. For example, to specify that a class inherits methods from the mx.events.EventDispatcher class, the fields can be declared as:
/** * @mixin mx.events.EventDispatcher#addEventListener */ public var addEventListener:Function; /** * @mixin mx.events.EventDispatcher#removeEventListener */ public var removeEventListener:Function;
Previous | Next |
Copyright 2003-2005 Kinesis Software. All rights reserved.