Difference between revisions of "Recital Object-Oriented Programming"
Barrymavin (Talk | contribs) |
Barrymavin (Talk | contribs) (→Recital Object-Oriented Programming) |
||
Line 1: | Line 1: | ||
==Recital Object-Oriented Programming== | ==Recital Object-Oriented Programming== | ||
− | === | + | ===Classes and Objects=== |
===What is a Class=== | ===What is a Class=== | ||
− | === | + | ===Class Members=== |
===What is Subclassing=== | ===What is Subclassing=== | ||
===Defining a Recital Class=== | ===Defining a Recital Class=== | ||
Line 14: | Line 14: | ||
===Extending with Classes Developed in C/C++=== | ===Extending with Classes Developed in C/C++=== | ||
===Summary=== | ===Summary=== | ||
+ | |||
+ | Recital is a dynamic programming language particularly suited to the development of database applications. While Recital still supports standard procedural programming, new extensions to the language give you the power and flexibility of object-oriented programming. Object-oriented design and object-oriented programming represent a change in focus from standard procedural programming. This short primer will give you a good understanding of how to program object-oriented Recital. <br /> | ||
+ | |||
+ | ===Classes and Objects=== | ||
+ | |||
+ | Classes and objects are closely related, but they are not the same. A class contains information about how an object should look and behave. A class is the blueprint or template for an object. | ||
+ | |||
+ | All of the properties and methods for an object are specified in the class definition. In addition, classes have the following characteristics that make them especially useful for creating reusable, easily maintained code: | ||
+ | |||
+ | + Encapsulation | ||
+ | + Subclasses | ||
+ | + Inheritance | ||
+ | + Interfaces | ||
+ | |||
+ | To define a class use the following syntax. | ||
+ | <pre> | ||
+ | class myclass | ||
+ | <members...> | ||
+ | endclass | ||
+ | </pre> | ||
+ | Then, to create an object based on this class use the following syntax. | ||
+ | |||
+ | myobject = new myclass() | ||
+ | |||
+ | ====Class members==== | ||
+ | Class members consists of properties (variables) and methods (procedures) that are encapsulated within the class declaration. | ||
+ | |||
+ | ====Properties==== | ||
+ | An object has certain properties, or attributes that are specific to the object. Properties are the equivalent of variables that can only be accessed by referencing them inside an object. By encapsulating the data (variables) and procedures within a class, programming becomes less error prone and applications easier to maintain. | ||
+ | |||
+ | Objects you create in Recital have properties that are determined by the class the object is based on. As Recital is a dynamic language, classes in Recital allow properties and methods to be added at run time. | ||
+ | |||
+ | <pre> | ||
+ | class myclass | ||
+ | myprop = “hello world” | ||
+ | endclass | ||
+ | |||
+ | myobject = new myclass() | ||
+ | echo myobject.myprop // displays "hello world" | ||
+ | </pre> | ||
+ | Properties defined within classes can be simple variables, fixed arrays, dynamic arrays or objects. | ||
+ | ====Methods==== | ||
+ | Methods are procedures that are associated with objects. Methods are different from normal Recital procedures in that they are bound with an object and are called differently from the way normal Recital procedures are called. | ||
+ | <pre> | ||
+ | class myclass | ||
+ | myprop = “Hello world” | ||
+ | public procedure mymethod() | ||
+ | echo myprop | ||
+ | endproc | ||
+ | endclass | ||
+ | |||
+ | myobject = new myclass() | ||
+ | myobject.mymethod() // displays "hello world"</pre> | ||
+ | |||
+ | ====Interface Methods==== | ||
+ | |||
+ | Interface Methods are template procedure definitions that must be implemented in any derived classes. | ||
+ | |||
+ | <pre> | ||
+ | class myclass | ||
+ | myprop = “Hello world” | ||
+ | public procedure mymethod() interface | ||
+ | endclass | ||
+ | |||
+ | myobject = new myclass() | ||
+ | myobject.mymethod() // throws an error "Interface method not defined"</pre> | ||
+ | |||
+ | ====Base Methods==== | ||
+ | All classes created inherit from the <strong>object</strong> class. The object class has a set of built-in methods that are available to all classes. | ||
+ | |||
+ | <table class="bordered"> | ||
+ | <tbody> | ||
+ | <tr> | ||
+ | <td><strong>Method</strong></td> | ||
+ | <td><strong> Description</strong></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>addproperty</td> | ||
+ | <td>Dynamically add a property to an object. <br /> | ||
+ | e.g. <br /> | ||
+ | object.addproperty("newproperty", expression)</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>removeproperty</td> | ||
+ | <td>Dynamically remove a property from an object. <br /> | ||
+ | e.g. <br /> | ||
+ | object.removeproperty("property")</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>clone</td> | ||
+ | <td>Clone this object. <br /> | ||
+ | e.g. <br /> | ||
+ | newobj = myobject.clone()</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>tostring</td> | ||
+ | <td>Returns a string describing the object <br /> | ||
+ | e.g. <br /> | ||
+ | // displays "myobj::myclass(n)" <br /> | ||
+ | // where (n) shows the reference count.<br /> | ||
+ | echo myobj.tostring()</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>class</td> | ||
+ | <td>Returns the classname of this object</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>instanceof</td> | ||
+ | <td>Returns True if this object is  an instance of the specified class<br /> | ||
+ | e.g.<br /> | ||
+ | result = myobj.instanceof("myclass")</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>equals</td> | ||
+ | <td>Compares the contents of two objects and returns True if they contain the same property values. If properties are arrays or other objects then the comparison is done recursively.</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>save</td> | ||
+ | <td>Saves an object to an external file (default extension .obf)<br /> | ||
+ | e.g.<br /> | ||
+ | myobj.save("save_myobj.obf")</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>load</td> | ||
+ | <td>Loads an object from an external file (default extension .obf)<br /> | ||
+ | e.g.<br /> | ||
+ | myobj.load("save_myobj.obf")</td> | ||
+ | </tr> | ||
+ | </tbody> | ||
+ | </table> | ||
+ | |||
+ | ====Member access control modifiers==== | ||
+ | You can 'hide' properties and methods using the access control modifiers protected, hidden, public, private, or static. | ||
+ | <pre> | ||
+ | class myclass | ||
+ | private myprop = “Hello world” | ||
+ | public procedure mymethod() | ||
+ | return myprop | ||
+ | endproc | ||
+ | public static procedure mystaticmethod() | ||
+ | endproc | ||
+ | endclass | ||
+ | |||
+ | myobject = new myclass() | ||
+ | // throws an error as "myprop" is private and can only be accessed by methods inside the class | ||
+ | echo myobject.myprop | ||
+ | myobject = new myclass() | ||
+ | // this will work. displays "hello world" | ||
+ | myobject.mymethod()</pre> | ||
+ | |||
+ | ====Special methods==== | ||
+ | Several methods hold special significance in a class. | ||
+ | |||
+ | <table border="0" class="bordered"> | ||
+ | <tbody> | ||
+ | <tr> | ||
+ | <td><strong>Name</strong></td> | ||
+ | <td><strong>Description</strong></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>init</td> | ||
+ | <td>Called after an object is first created. This is a known as the constructor method.</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>Destroy</td> | ||
+ | <td>Called just prior to an object being destroyed. This is known as the destructor method.</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>property_access</td> | ||
+ | <td>Property access notification.</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>property_assign</td> | ||
+ | <td>Property assignment notification.</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>this_access</td> | ||
+ | <td>Property access notification.</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>this_assign</td> | ||
+ | <td>Property assignment notification.</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>error</td> | ||
+ | <td>Class specific error handler.</td> | ||
+ | </tr> | ||
+ | </tbody> | ||
+ | </table> | ||
+ | |||
+ | ===Class inheritance=== | ||
+ | There are many benefits of inheritance with Recital, the most common is simplifying and reducing instances of redundant code. Recital supports multiple levels of inheritance. A class that inherits a parent class is said to be a 'subclass' of the parent. | ||
+ | <pre> | ||
+ | class product | ||
+ | public name | ||
+ | public price | ||
+ | proc init(cName, nPrice) // contructor | ||
+ | name = cName | ||
+ | price = nPrice | ||
+ | endproc | ||
+ | proc display() | ||
+ | echo "Product name is " + name + ", price is " + price | ||
+ | endproc | ||
+ | endclass | ||
+ | |||
+ | class food as product | ||
+ | private weight | ||
+ | endclass | ||
+ | |||
+ | class car as product | ||
+ | private color | ||
+ | endclass | ||
+ | |||
+ | class motorbike as product | ||
+ | private size | ||
+ | endclass | ||
+ | |||
+ | // now define a vehicle class that inherits from multiple classes (car and motorbike) | ||
+ | class vehicle as car,motorbike | ||
+ | public manufacturer = "Ford" | ||
+ | public yearDesigned | ||
+ | proc init(cName, nPrice) // contructor | ||
+ | manufacturer = cName | ||
+ | price = nPrice | ||
+ | endproc | ||
+ | proc display() | ||
+ | echo "Manufacturer is " + manufacturer + ", price is " + price | ||
+ | endproc | ||
+ | endclass | ||
+ | |||
+ | // create a new object | ||
+ | myobject = new vehicle("Ford", 20000) | ||
+ | myobject.display() // displays "Manufacturer is Ford, price is 20000 | ||
+ | |||
+ | myobject = new motorbike("Honda", 1500) | ||
+ | myobject.display() // displays "Product name is Honda, price is 20000</pre> | ||
+ | |||
+ | ===Overriding methods=== | ||
+ | As can be seen by the above example of class inheritance, you can override methods of parent classes that you inherit. If you want to call the parent class method of the same name from within a subclass, then use the dodefault() method. Note that because Recital handles multiple inheritance, and because a subclass can only have one 'parent' the last class inherited is denoted as the parent and is called by dodefault(). | ||
+ | <pre> | ||
+ | // now define a vehicle class that inherits from multiple classes (car and motorbike) | ||
+ | class vehicle as car,motorbike | ||
+ | public manufacturer = "Ford" | ||
+ | public yearDesigned | ||
+ | proc init(cName, nPrice) // contructor | ||
+ | manufacturer = cName | ||
+ | name = cName | ||
+ | price = nPrice | ||
+ | endproc | ||
+ | proc display() | ||
+ | dodefault() // calls the 'display()' method in the parent class 'product' | ||
+ | echo "Manufacturer is " + manufacturer + ", price is " + price | ||
+ | endproc | ||
+ | endclass</pre> | ||
+ | |||
+ | ===Scope resolution operator=== | ||
+ | The scope resolution operator :: can be used to reference static methods and properties in classes. | ||
+ | <pre> | ||
+ | class myclasslib | ||
+ | public static mydata = array() | ||
+ | public static proc display(arg) | ||
+ | echo arg | ||
+ | endproc | ||
+ | endclass | ||
+ | </pre> | ||
+ | We can call the display method without instantiating an object because it is declared static e.g. | ||
+ | <pre> | ||
+ | myclasslib::display("hello world")</pre> | ||
+ | We can access "mydata" without instantiating an object because it is declared static e.g. | ||
+ | <pre> | ||
+ | myclasslib::mydata("key") = "value"</pre> | ||
+ | |||
+ | ===Special variables=== | ||
+ | There are several special built-in object variables that can be used. | ||
+ | |||
+ | <table class="bordered"> | ||
+ | <tbody> | ||
+ | <tr> | ||
+ | <td><strong>Object </strong></td> | ||
+ | <td><strong> Description </strong></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>this</td> | ||
+ | <td>A reference to the currently executing object</td> | ||
+ | </tr> | ||
+ | </tbody> | ||
+ | </table> | ||
+ | |||
+ | ====Iterating through object properties==== | ||
+ | You can iterate over the properties of an object using the <strong>foreach</strong> command like this. | ||
+ | <pre> | ||
+ | // create a new object | ||
+ | myobject = new myclass() | ||
+ | |||
+ | // iterate over its properties | ||
+ | foreach myobject as name => value | ||
+ | echo "name=" + name + ", value=" + value // displays "name=MYPROP, value=hello world" | ||
+ | endfor</pre> | ||
+ | |||
+ | ===Dynamically adding and removing properties runtime=== | ||
+ | As Recital is a dynamic language, object properties can be added and removed dynamically at runtime. | ||
+ | <pre> | ||
+ | // create a new object | ||
+ | myobject = new myclass() | ||
+ | |||
+ | // extend it by adding a property at runtime | ||
+ | myobject.addproperty("date", date()) | ||
+ | |||
+ | // now remove it | ||
+ | myobject.removeproperty('date')</pre> | ||
+ | |||
+ | ===Dynamically assigning methods at runtime=== | ||
+ | As Recital is a dynamic language, methods can be assigned to objects dynamically at runtime. | ||
+ | <pre> | ||
+ | // create a new object | ||
+ | myobject = new myclass() | ||
+ | |||
+ | // dynamically add a method | ||
+ | procedure mynewmethod() | ||
+ | echo "hello world" | ||
+ | endproc | ||
+ | |||
+ | myobject.newmethod = mynewmethod | ||
+ | myobject.newmethod() // displays "hello world"</pre> | ||
+ | ====Runtime data-type checking==== | ||
+ | You can restrict what types of data can be assigned to properties using the "as datatype" clause. | ||
+ | |||
+ | The following datatypes are supported. | ||
+ | |||
+ | <table border="0" class="bordered"> | ||
+ | <tbody> | ||
+ | <tr> | ||
+ | <td><strong>Type</strong></td> | ||
+ | <td><strong>Description</strong></td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>character</td> | ||
+ | <td>can assign character data</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>numeric</td> | ||
+ | <td>can assign numeric data</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>date</td> | ||
+ | <td>can assign date data</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>logical</td> | ||
+ | <td>can assign logical data</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>datetime</td> | ||
+ | <td>can assign datetime data</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>currency</td> | ||
+ | <td>can assign currency data</td> | ||
+ | </tr> | ||
+ | <tr> | ||
+ | <td>class</td> | ||
+ | <td>Name of user-defined class</td> | ||
+ | </tr> | ||
+ | </tbody> | ||
+ | </table> | ||
+ | |||
+ | <pre> | ||
+ | define class myclass | ||
+ | public myprop as character = “Hello world” | ||
+ | public procedure mymethod() | ||
+ | return myprop | ||
+ | endproc | ||
+ | static procedure mystaticmethod() | ||
+ | endproc | ||
+ | enddefine | ||
+ | |||
+ | // create a new object | ||
+ | myobject = new myclass() | ||
+ | myobject.myprop = "this is data" // works ok | ||
+ | myobject.myprop = 10 // throws an error because we defined "myprop as character"</pre> | ||
+ | ====Understanding member lookup==== | ||
+ | Recital variables and procedures are declared in a hashed, block structured symbol table. Each procedure, function or method that is executed increases the runtime "level". Any variables or procedures that are referenced are looked up in decreasing runtime execution level order until found. In the case of object methods, the Recital runtime engine will first look in the active object for properties and methods. If not found, then it will carry out a standard symbol table lookup in decreasing runtime level order. This technique allows classes to be easily integrated into an existing application, and provides the ability for object methods to reference global variables and call global procedures. | ||
+ | |||
+ | ===The life of an object=== | ||
+ | Recital uses object reference counting to handle automatic garbage collection. | ||
+ | |||
+ | When an object is created its reference count is set to 1. All assignments of objects to other variables or procedure/function arguments cause the reference count to be incremented. An object is released from memory (dereferenced) when its reference count reaches zero. | ||
+ | |||
+ | To dereference an object you simply assign another value to it. e.g. | ||
+ | <pre> | ||
+ | // create a new object (and set its reference count to 1) | ||
+ | myobject = new myclass() | ||
+ | |||
+ | // now free up the object. This will decrement the reference count associated with the object. | ||
+ | // When the reference count is 0 then the object will be released from memory (dereferenced). | ||
+ | myobject = null | ||
+ | |||
+ | // In this example the object is not released as it is still referenced by 'myvar' | ||
+ | myobject = new myclass() | ||
+ | myvar = myobject | ||
+ | myobject = null | ||
+ | |||
+ | // now it will be released | ||
+ | myvar = null | ||
+ | </pre> | ||
+ | If an object property (variable) is an object reference, when the object containing the property (variable) is released (dereferenced) than the reference count of all object variables is decremented, and when the reference count reaches zero, then that object is released from memory. | ||
+ | |||
+ | ===Writing and using class libraries=== | ||
+ | Once you have completed the development of your class library you can use the classes within your programs like this. | ||
+ | |||
+ | require_once("myclasslib.prg") | ||
+ | |||
+ | The require_once( ) function will include the specified class library into your program only if it has not already been included and execute it at the current execution level. This will make all classes (also variables, procedures and functions) available to the calling program and all programs or procedures that it calls. | ||
+ | |||
+ | The specified class library is compiled into a Recital object file and loaded into shared global memory. This provides for optimal memory usage and also improved application performance as the class library is only loaded once. When class/procedure libraries (and in fact all Recital web .rsp files) are loaded like this in Recital Web them memory usage will be reduced dramatically. |
Revision as of 00:33, 24 October 2009
Contents
- 1 Recital Object-Oriented Programming
- 1.1 Classes and Objects
- 1.2 What is a Class
- 1.3 Class Members
- 1.4 What is Subclassing
- 1.5 Defining a Recital Class
- 1.6 Recital Class Constructors and Destructors
- 1.7 Creating Members in a Recital Class
- 1.8 Defining and Calling Methods
- 1.9 Subclassing in Recital
- 1.10 Recital Object Serialization
- 1.11 Getting Information about a Recital Object
- 1.12 Understanding Reference Counting
- 1.13 Extending with Classes Developed in C/C++
- 1.14 Summary
- 1.15 Classes and Objects
- 1.16 Class inheritance
- 1.17 Overriding methods
- 1.18 Scope resolution operator
- 1.19 Special variables
- 1.20 Dynamically adding and removing properties runtime
- 1.21 Dynamically assigning methods at runtime
- 1.22 The life of an object
- 1.23 Writing and using class libraries
Recital Object-Oriented Programming
Classes and Objects
What is a Class
Class Members
What is Subclassing
Defining a Recital Class
Recital Class Constructors and Destructors
Creating Members in a Recital Class
Defining and Calling Methods
Subclassing in Recital
Recital Object Serialization
Getting Information about a Recital Object
Understanding Reference Counting
Extending with Classes Developed in C/C++
Summary
Recital is a dynamic programming language particularly suited to the development of database applications. While Recital still supports standard procedural programming, new extensions to the language give you the power and flexibility of object-oriented programming. Object-oriented design and object-oriented programming represent a change in focus from standard procedural programming. This short primer will give you a good understanding of how to program object-oriented Recital.
Classes and Objects
Classes and objects are closely related, but they are not the same. A class contains information about how an object should look and behave. A class is the blueprint or template for an object.
All of the properties and methods for an object are specified in the class definition. In addition, classes have the following characteristics that make them especially useful for creating reusable, easily maintained code:
+ Encapsulation + Subclasses + Inheritance + Interfaces
To define a class use the following syntax.
class myclass <members...> endclass
Then, to create an object based on this class use the following syntax.
myobject = new myclass()
Class members
Class members consists of properties (variables) and methods (procedures) that are encapsulated within the class declaration.
Properties
An object has certain properties, or attributes that are specific to the object. Properties are the equivalent of variables that can only be accessed by referencing them inside an object. By encapsulating the data (variables) and procedures within a class, programming becomes less error prone and applications easier to maintain.
Objects you create in Recital have properties that are determined by the class the object is based on. As Recital is a dynamic language, classes in Recital allow properties and methods to be added at run time.
class myclass myprop = “hello world” endclass myobject = new myclass() echo myobject.myprop // displays "hello world"
Properties defined within classes can be simple variables, fixed arrays, dynamic arrays or objects.
Methods
Methods are procedures that are associated with objects. Methods are different from normal Recital procedures in that they are bound with an object and are called differently from the way normal Recital procedures are called.
class myclass myprop = “Hello world” public procedure mymethod() echo myprop endproc endclass myobject = new myclass() myobject.mymethod() // displays "hello world"
Interface Methods
Interface Methods are template procedure definitions that must be implemented in any derived classes.
class myclass myprop = “Hello world” public procedure mymethod() interface endclass myobject = new myclass() myobject.mymethod() // throws an error "Interface method not defined"
Base Methods
All classes created inherit from the object class. The object class has a set of built-in methods that are available to all classes.
Method | Description |
addproperty | Dynamically add a property to an object. e.g.object.addproperty("newproperty", expression) |
removeproperty | Dynamically remove a property from an object. e.g.object.removeproperty("property") |
clone | Clone this object. e.g.newobj = myobject.clone() |
tostring | Returns a string describing the object e.g.echo myobj.tostring() |
class | Returns the classname of this object |
instanceof | Returns True if this object is an instance of the specified classe.g.result = myobj.instanceof("myclass") |
equals | Compares the contents of two objects and returns True if they contain the same property values. If properties are arrays or other objects then the comparison is done recursively. |
save | Saves an object to an external file (default extension .obf)e.g.myobj.save("save_myobj.obf") |
load | Loads an object from an external file (default extension .obf)e.g.myobj.load("save_myobj.obf") |
Member access control modifiers
You can 'hide' properties and methods using the access control modifiers protected, hidden, public, private, or static.
class myclass private myprop = “Hello world” public procedure mymethod() return myprop endproc public static procedure mystaticmethod() endproc endclass myobject = new myclass() // throws an error as "myprop" is private and can only be accessed by methods inside the class echo myobject.myprop myobject = new myclass() // this will work. displays "hello world" myobject.mymethod()
Special methods
Several methods hold special significance in a class.
Name | Description |
init | Called after an object is first created. This is a known as the constructor method. |
Destroy | Called just prior to an object being destroyed. This is known as the destructor method. |
property_access | Property access notification. |
property_assign | Property assignment notification. |
this_access | Property access notification. |
this_assign | Property assignment notification. |
error | Class specific error handler. |
Class inheritance
There are many benefits of inheritance with Recital, the most common is simplifying and reducing instances of redundant code. Recital supports multiple levels of inheritance. A class that inherits a parent class is said to be a 'subclass' of the parent.
class product public name public price proc init(cName, nPrice) // contructor name = cName price = nPrice endproc proc display() echo "Product name is " + name + ", price is " + price endproc endclass class food as product private weight endclass class car as product private color endclass class motorbike as product private size endclass // now define a vehicle class that inherits from multiple classes (car and motorbike) class vehicle as car,motorbike public manufacturer = "Ford" public yearDesigned proc init(cName, nPrice) // contructor manufacturer = cName price = nPrice endproc proc display() echo "Manufacturer is " + manufacturer + ", price is " + price endproc endclass // create a new object myobject = new vehicle("Ford", 20000) myobject.display() // displays "Manufacturer is Ford, price is 20000 myobject = new motorbike("Honda", 1500) myobject.display() // displays "Product name is Honda, price is 20000
Overriding methods
As can be seen by the above example of class inheritance, you can override methods of parent classes that you inherit. If you want to call the parent class method of the same name from within a subclass, then use the dodefault() method. Note that because Recital handles multiple inheritance, and because a subclass can only have one 'parent' the last class inherited is denoted as the parent and is called by dodefault().
// now define a vehicle class that inherits from multiple classes (car and motorbike) class vehicle as car,motorbike public manufacturer = "Ford" public yearDesigned proc init(cName, nPrice) // contructor manufacturer = cName name = cName price = nPrice endproc proc display() dodefault() // calls the 'display()' method in the parent class 'product' echo "Manufacturer is " + manufacturer + ", price is " + price endproc endclass
Scope resolution operator
The scope resolution operator :: can be used to reference static methods and properties in classes.
class myclasslib public static mydata = array() public static proc display(arg) echo arg endproc endclass
We can call the display method without instantiating an object because it is declared static e.g.
myclasslib::display("hello world")
We can access "mydata" without instantiating an object because it is declared static e.g.
myclasslib::mydata("key") = "value"
Special variables
There are several special built-in object variables that can be used.
Object | Description |
this | A reference to the currently executing object |
Iterating through object properties
You can iterate over the properties of an object using the foreach command like this.
// create a new object myobject = new myclass() // iterate over its properties foreach myobject as name => value echo "name=" + name + ", value=" + value // displays "name=MYPROP, value=hello world" endfor
Dynamically adding and removing properties runtime
As Recital is a dynamic language, object properties can be added and removed dynamically at runtime.
// create a new object myobject = new myclass() // extend it by adding a property at runtime myobject.addproperty("date", date()) // now remove it myobject.removeproperty('date')
Dynamically assigning methods at runtime
As Recital is a dynamic language, methods can be assigned to objects dynamically at runtime.
// create a new object myobject = new myclass() // dynamically add a method procedure mynewmethod() echo "hello world" endproc myobject.newmethod = mynewmethod myobject.newmethod() // displays "hello world"
Runtime data-type checking
You can restrict what types of data can be assigned to properties using the "as datatype" clause.
The following datatypes are supported.
Type | Description |
character | can assign character data |
numeric | can assign numeric data |
date | can assign date data |
logical | can assign logical data |
datetime | can assign datetime data |
currency | can assign currency data |
class | Name of user-defined class |
define class myclass public myprop as character = “Hello world” public procedure mymethod() return myprop endproc static procedure mystaticmethod() endproc enddefine // create a new object myobject = new myclass() myobject.myprop = "this is data" // works ok myobject.myprop = 10 // throws an error because we defined "myprop as character"
Understanding member lookup
Recital variables and procedures are declared in a hashed, block structured symbol table. Each procedure, function or method that is executed increases the runtime "level". Any variables or procedures that are referenced are looked up in decreasing runtime execution level order until found. In the case of object methods, the Recital runtime engine will first look in the active object for properties and methods. If not found, then it will carry out a standard symbol table lookup in decreasing runtime level order. This technique allows classes to be easily integrated into an existing application, and provides the ability for object methods to reference global variables and call global procedures.
The life of an object
Recital uses object reference counting to handle automatic garbage collection.
When an object is created its reference count is set to 1. All assignments of objects to other variables or procedure/function arguments cause the reference count to be incremented. An object is released from memory (dereferenced) when its reference count reaches zero.
To dereference an object you simply assign another value to it. e.g.
// create a new object (and set its reference count to 1) myobject = new myclass() // now free up the object. This will decrement the reference count associated with the object. // When the reference count is 0 then the object will be released from memory (dereferenced). myobject = null // In this example the object is not released as it is still referenced by 'myvar' myobject = new myclass() myvar = myobject myobject = null // now it will be released myvar = null
If an object property (variable) is an object reference, when the object containing the property (variable) is released (dereferenced) than the reference count of all object variables is decremented, and when the reference count reaches zero, then that object is released from memory.
Writing and using class libraries
Once you have completed the development of your class library you can use the classes within your programs like this.
require_once("myclasslib.prg")
The require_once( ) function will include the specified class library into your program only if it has not already been included and execute it at the current execution level. This will make all classes (also variables, procedures and functions) available to the calling program and all programs or procedures that it calls.
The specified class library is compiled into a Recital object file and loaded into shared global memory. This provides for optimal memory usage and also improved application performance as the class library is only loaded once. When class/procedure libraries (and in fact all Recital web .rsp files) are loaded like this in Recital Web them memory usage will be reduced dramatically.