Purpose | The <class> statement is used to define a class and load it into the run-time class memory or to redefine an existing class. | |||||||||||||||||||||||||||||||||||
Format |
<class name="{class name}" inherit="{comma-separated list of parent classes}"> <construct> <scope type="{scope specifier}"> <{descendant nodes}> </scope> </construct> <scope type="{scope specifier}"> <func name="{method name}" type="{method type}"> <parm type="{parm type}" name="{parm name}" pass="{parm pass type}"> {parm value} </parm> . . . <body> {method statements} </body> </func> </scope> <scope type="{scope specifier}"> <var type="{member var type}" name="{member var name}">{initial value}</var> . . . <arr type="{member arr type}" name="{member arr name and size}">{initial values}<arr> . . . </scope> </class>
{class name} |
the name of the class being defined and loaded into run-time class memory. |
{comma-separated list of parent classes} |
the comma-separated list of the names of the parent classes from which this class inherits properties and behaviour-- use "" if the class does not inherit from any other. |
{scope specifier} |
defines the accessibility of the embedded items: can be public, protected or private. |
{descendant nodes} |
the actual XML renderings of contained objects that are to be automatically instantiated whenever an object of this class is instantiated. |
{method name} |
the name of a method that implements a behaviour in this class. |
{method type} |
the datatype of the returned value of the method: use void if there is no returned value. |
{parm name} |
the name of a parameter that is passed into the method. |
{parm type} |
the datatype of a parameter that is passed into the method. |
{parm pass type} |
the type of parameter passing: val or "" means pass by value; ref means pass by reference. |
{parm value} |
the value of a parameter that is passed into the method. |
{method statements} |
the statements to be executed when the method is invoked. |
{member var type} |
the datatype of a member variable of the class. |
{member var name} |
the name of the member variable. |
{initial value} |
the initial value of the member variable that it is set to when an object of the class is instantiated. |
{member arr type} |
the datatype of a member array of the class. |
{member arr name and size} |
the name and number of elements in the member array. |
{initial values} |
the comma-separated list of initial values of the member array elements bounded by curly braces. |
|
|
<construct> | ||||||||||||||||||||||||||||||||||||
The <construct> clause is refered to as the structural constructor. Its purpose is to define the set of contained objects/nodes for the class. Each of these nodes may inherit from other classes by means of the class attribute. The object that is instantiated from the class which owns the <construct> clause will contain nodes as specified in the clause. | ||||||||||||||||||||||||||||||||||||
Inheritance | ||||||||||||||||||||||||||||||||||||
Single inheritance is implemented in a class by writing the name of only one class in the inherit attribute of the <class> statement. Multiple inheritance is achieved by writing more than one class name in the inherit attribute. A node defined in the <construct> clause specifies single or multiple inheritance by writing the name(s) of the class(es) in the node's class attribute. An instance of the class defined in the <class> statement implements single or multiple inheritance by writing the name(s) of the class(es) it inherits from in the class attribute of the <node> statement that instantiated it. Please note that if the inherit or class attributes are empty, the node will inherit only from the Node abstract class. | ||||||||||||||||||||||||||||||||||||
Function/Method Invocation | ||||||||||||||||||||||||||||||||||||
Methods are invoked via the <eval> statement. Methods that take parameters will have these passed to them within the <parm> clauses of the <eval> statements that invoke the methods. The parameters may be passed by value or by reference. <eval object="{object name}" executeclass="{ancestral class}" member="{method name}"> {parameters} </eval> In the above statement the {object name} is the name of the object owning the method and the executeclass is the special attribute of the <eval> statement that specifies which class will handle the method call. The {ancestral class} specifies the name of the class to handle the method call. The {method name} is the name of the method to be invoked and the {parameters} are the required parameters of the method. In normal circumstances you will omit the executeclass attribute and let the Superx++ run-time engine resolve the appropriate class to handle the method. Method resolution is done by finding the first class that implements a method in the inherit or class attributes. From there resolution moves up the inheritance hierarchy if the method was not yet found. |
||||||||||||||||||||||||||||||||||||
Function/Method Return Values | ||||||||||||||||||||||||||||||||||||
Methods can return a value back to the calling portion of a program. This is why the <func> clause contains a datatype. The value is returned back to the caller via the <return> statement. When the <return> statement executes it passes back the return value to the caller and terminates the method. The <return> statement can also be found within the main part of a Superx++ program in which case the program terminates. There is no value passed back to the caller of the Superx++ program. <return> {return value} </return> In the above statement the {return value} is the value that is to be passed back to the caller. The method then terminates at this point. |
||||||||||||||||||||||||||||||||||||
Function/Method Over-riding | ||||||||||||||||||||||||||||||||||||
Function over-riding is implemented when a class inherits from another class and implements another version of a method found in the ancestral class. It is possible to invoke the method found in the ancestral class (at any level-- not just the parent/super class) by means of the <eval> statement of the following format: <eval object="this" executeclass="{ancestral class}" member="{method name}"> {parameters} </eval> In the above statement the executeclass is the special attribute of the <eval> statement that specifies which class will handle the method call. The {ancestral class} specifies the name of the class to handle the method call. The {method name} is the name of the method to be invoked and the {parameters} are the required parameters of the method. |
||||||||||||||||||||||||||||||||||||
Class Redefinition | ||||||||||||||||||||||||||||||||||||
Class redefinition is implemented by the execution of a subsequent <class> statement which contains the same value in the name attribute as a previously defined class. All objects that are instantiated using the definition found in the original <class> statement will still exist after the class redefinition. They will be modified in the following manner: Their methods will be the ones defined in the redefining <class> statement
However, the formerly instantiated objects will remain the same in every other regard, that is:
Newly instantiated objects after the redefinition will be defined completely after the redefined form. They will therefore differ from their older relatives as follows: |
||||||||||||||||||||||||||||||||||||
Condition Class Definition (Polymorphic Class Definition) | ||||||||||||||||||||||||||||||||||||
Conditional class definition is implemented by the execution of a <class> statement within a conditional statement such as an <if> or a <switch> statement. Here is an example: <if> <cond> <eval> <parm type="string" name="rev">old</parm> <expr>rev = "new"</expr> </eval> </cond> <true> <class name="XPlant"> <construct> <Age /> </construct> <scope type="public"> <var type="string" name="Species" /> </scope> </class> </true> <false> <class name="XPlant" inherit="XTree"> <construct> <Age /> <Size /> </construct> <scope type="public"> <var type="string" name="Species" /> </scope> </class> </false> </if> In this example above we have two different definitions of the same class, XPlant. If the rev parameter is set to new then the <class> statement in the <true> clause of the <if> statement executes and defines the XPlant class in one way. If the rev parameter is not set to new then the <class> statement in the <false> clause of the <if> statement executes and defines the XPlant class the other way. An obvious advantage to this polymorphic definition of the class is in the case of versioning. If you have two versions of a program, then you can use the old class definition for the old version and the new class definition for the new version. The possibilities are limited to your imagination with what you can do with polymorphic class definition. |
||||||||||||||||||||||||||||||||||||
Method Classes | ||||||||||||||||||||||||||||||||||||
It is possible to define classes within methods of other classes. This has the benefit of creating temporary types that are disposed of automatically once they are used. So you create the class within your method and use it there. Then once the method terminates the class is automatically deleted from class memory. Here is an example: <class name="XCalc"> <construct /> <scope type="public"> <func type="int" name="SpecialCalc"> <parm type="int" name="op1" /> <parm type="int" name="op2" /> <body> <class name="XTemp"> <construct /> <scope type="public"> <func type="int" name="Do"> <parm type="int" name="a1" /> <parm type="int" name="a2" /> <body> <return> <eval> <parm type="int" name="a"><eval object="a1" /></parm> <parm type="int" name="b"><eval object="a2" /></parm> <expr>a + b</expr> </eval> </return> </body> </func> </scope> </class> <node name="TempObj" class="XTemp" /> <return> <eval object="TempObj" member="Do"> <parm type="int" name="a1"><eval object="op1" /></parm> <parm type="int" name="a2"><eval object="op2" /></parm> </eval> </return> </body> </func> </scope> </class> <node name="MyCalc" class="XCalc" /> <xout>The calculation yields </xout> <xout> <eval object="MyCalc" member="SpecialCalc"> <parm type="int" name="op1">200</parm> <parm type="int" name="op2">300</parm> </eval> </xout> In this example above we have a class XCalc which has a method SpecialCalc. SpecialCalc contains a class XTemp which performs the real calculation. In this case, it is simple addition but more complex logic could be included. The benefit is that the XTemp class with its special logic is deleted from class memory once the method that defines it terminates. |
||||||||||||||||||||||||||||||||||||
Examples | ||||||||||||||||||||||||||||||||||||
Example #1 |
<class name="XPlant" inherit=""> <construct> <scope type="protected"> <Size units="feet">50</Size> </scope> </construct> <scope type="public"> <func name="GetSize" type="int"> <body> <return> <eval object="Size" /> </return> </body> </func> </scope> </class>
<node name="AppleTree" class="XPlant" /> The class XPlant is defined above with a single contained node, Size, which contains an attribute, units, with the value, feet. Size is a protected object within the class so no code outside the class can access it. We therefore have a method to access it called GetSize which takes no parameters and whose return value is an int. The <node> statement is not part of the class definition. It is the instruction that performs the instantiation of the object, AppleTree, which is an object of class, XPlant. We then use the <eval> statement to invoke the GetSize method and we use the <xout> statement to send the returned value to the output stream. The result is that the following text is sent to the output stream: The size of the AppleTree is 50. |
|||||||||||||||||||||||||||||||||||
Example #2 |
<class name="XPlant" inherit=""> <construct> <scope type="protected"> <Size units="feet">50</Size> </scope> </construct> <scope type="public"> <func name="GetSize" type="int"> <body> <return> <eval object="Size" /> </return> </body> </func> <var name="FruitBearing" type="string">yes</var> <arr name="ProfitPerYear[3]" type="string">{200,150,127}</arr> </scope> </class>
<node name="AppleTree" class="XPlant" />
The class XPlant is the same as in Example #1 above with some changes. In this example, the member variable and the member array are invoked. The net result is that the following text is sent to the output stream on separate lines: |
|||||||||||||||||||||||||||||||||||
Example #3 |
<class name="XPlant" inherit=""> <construct> <scope type="protected"> <Size units="feet">50</Size> </scope> </construct> <scope type="public"> <func name="GetSize" type="int"> <body> <return> <eval object="Size" /> </return> </body> </func> <func name="GetUnits" type="void"> <parm type="string" name="a_Units" pass="ref" /> <body> <eval object="a_Units"> <eval object="Size" attribute="units" /> </eval> </body> </func> <var name="FruitBearing" type="string">yes</var> <arr name="ProfitPerYear[3]" type="string">{200,150,127}</arr> </scope> </class>
<node name="AppleTree" class="XPlant" />
The class XPlant is the same as in Example #1 above with some changes. In this example, the method, GetUnits is invoked. GetUnits takes a single parameter by reference, a_Units, which is a string. a_Units is assigned the value of the units attribute in the Size contained node. In the main part of the program, the <var> statement creates a variable called MyUnits which is passed by reference into GetUnits which in turn fills MyUnits with the contents of the units attribute of the Size object. This is done due to the referential link between a_Units and MyUnits which is created in the <parm> clause in the <eval> statement that invokes GetUnits. The net result is that the following text is sent to the output stream on separate lines: |
|||||||||||||||||||||||||||||||||||
Example #4 |
<class name="XPlant" inherit=""> <construct> <scope type="protected"> <Size units="feet">50</Size> </scope> </construct> <scope type="public"> <func name="GetSize" type="int"> <body> <return> <eval object="Size" /> </return> </body> </func> <func name="GetUnits" type="void"> <parm type="string" name="a_Units" pass="ref" /> <body> <eval object="a_Units"> <eval object="Size" attribute="units" /> </eval> </body> </func> <var name="FruitBearing" type="string">yes</var> <arr name="ProfitPerYear[3]" type="string">{200,150,127}</arr> </scope> </class>
<class name="XTree" inherit="XPlant">
<node name="AppleTree" class="XTree" />
The class XPlant is the same as in Example #3 above; however the class XTree inherits from it (this is an example of single-inheritance) and the AppleTree is instantiated as an instance of the XTree class. The class XTree inherits the methods and members of the XPlant class and so the AppleTree instance has them also. In this example, the method, GetUnits is invoked. GetUnits takes a single parameter by reference, a_Units, which is a string. a_Units is assigned the value of the units attribute in the Size contained node. In the main part of the program, the <var> statement creates a variable called MyUnits which is passed by reference into GetUnits which in turn fills MyUnits with the contents of the units attribute of the Size object. This is done due to the referential link between a_Units and MyUnits which is created in the <parm> clause in the <eval> statement that invokes GetUnits. The invocation of the DoBirdsLike method is obvious enough and the returned value is fed as the argument of the <xout> statement. However, the call to the SetBirdsLike method is special because that method changes the value of the member variable, BirdsLike; thus, the next time that the DoBirdsLike method is called yields false rather than true as before. The net result is that the following text is sent to the output stream on separate lines: |