1. Objects & Classes
is a data structure that provides properties
Objects are accessed "by reference", i.e. by using a pointer to it, i.e. by using a variable
whose value is the address of the object
data structure in memory.
data structure is described by a class
So each Gambas
object has a class
that describes all its public properties, methods and events.
This class is a Gambas
object too, whose class is the class named Class
A static class
is a class whose all members are static
(see below). In Gambas
, a static class
is also named a module
A static class cannot be instanciated: it would create an object
with no dynamic variable
, which is useless.
A virtual class
is an hidden pseudo-class that you cannot explicitely manipulate.
1.2. Properties, methods and variables
Properties and methods allow to manipulate the data structure.
A property, a method or a variable can be static
- A static variable will be shared by all instances of the same class.
- A static property or method can only modify static variables.
A method or a variable can be either public
. A property is always public.
Private symbols can only be used from the class inside.
Public symbols can be used everywhere, provided you have a reference pointing at the object.
There is no garbage collector
. So each object has a reference counter
that is incremented each time the object is referenced by any variable
, array, collection or other object, and decremented when it is released.
This reference counter is zero at object creation, and when it becomes zero again after a reference release, the object is freed.
1.4. Invalid objects
An object can become invalid
. Because, for example, it is linked to an internal object not managed by Gambas
that was destroyed.
Trying to use an invalid object raises an error.
1.5. Special methods
Special methods are methods declared in classes, whose name begins with an underscore character, and that are called by the interpreter in the following situations:
- When an object is created.
- When an object is freed.
- When the object class is loaded.
- When the object class is unloaded.
- When using an object as if it is an array.
- When enumerating the object.
- When using an object as if it is a function.
- When trying to use an unknown object method or property.
See Special Methods
and Special Methods
for more information.
2. Events & Observers
Events are signals sent by an object when something happens on it.
If an object raises events, it will hold a reference on its observer
, or parent object
This observer is another object that implements event handlers
. An event handler
is just a public method
that is called each time the event
By default, the observer is the current object where the newly instanciated object is declared.
To raise events, an object must have an event name
. This event name is assigned at object instanciation, when using the NEW
instruction and the AS
keyword, and is the prefix of all event handler methods.
This creates a Button
control that will raise events.
DIM hButton AS Button
hButton = NEW Button(ME) AS "ButtonEventName"
If no event name is specified, then the object
won't raise events.
2.2. Locking Objects
An object can be locked so that it stops raising events, and can be unlocked so that it raises them again.
See the Object.Lock
Some events can be cancelled by the event handler, by using the STOP EVENT
The effect of this cancellation depends on the event
are objects that allow you to intercept events raised by other objects. They "observe" them.
You can intercept events just before they have been raised, or just after.
For each intercepted event
, the observer will raise an event with the same name and the same arguments.
By using STOP EVENT
inside an observer event handler, you cancel the original event.
PRIVATE $hButton as Button
PRIVATE $hObserver AS Observer
PUBLIC SUB Form_Load()
$hButton = NEW Button(ME) AS "Button"
$hObserver = NEW Observer(hButton) AS "Observer"
PUBLIC SUB Observer_Click()
DEBUG "The button has been clicked. I cancel the event!"
PUBLIC SUB Button_Click()
DEBUG "You should not see me."
Inheritance is the way for a class to become a specialized version of another class.
3.1. What is inherited?
The class inherits from its parent every method
3.2. Which class can be a parent class?
You can inherited any class, even a native one!
For example, you can create
a custom MyListBox class that inherits ListBox
but allows to associate a tag with each list item.
Note that you cannot use INHERITS
in a form class file, because forms already
inherits the Form
3.3. Virtual dispatching
When calling a method
or accessing a property
from an object reference, Gambas
uses virtual dispatching
It means that the real class of the object is always used, and
not the type of the variable
that references the object - As it was in Gambas
3.4. Inheritance and constructor
Contrary to all the object language I know, each class in the inheritance
hierarchy consumes the parameters passed to the constructor.
Let's suppose we have the following inheritance tree:
MyListBox ---inherits--> ListBox ---inherits---> Control
- Control._new() does not exist.
- ListBox._new() takes one parameter: the parent control.
- MyListBox._new() takes one parameter: a name - It is just an example.
So NEW MyListBox
will take two parameters.
- The first will be sent to MyListBox._new().
- The second to ListBox._new().
Be careful: the ListBox
._new() will be called first,
so that you are sure that the ListBox
when you are in MyListBox._new().
Then you will create a MyListBox control this way:
hMyListBox = NEW MyListBox("Name", hContainer)
So the order of arguments is the following:
- Mandatory arguments are consumed first, and then optional arguments if they are available.
- The arguments of elder classes are specified first.
For example, if you have the following inheritance:
MyForm --> Form --> Window
with the MyForm constructor being:
Sub _new(FirstArg As String, SecondArg as Integer, Optional ThirdArg As Integer)
Note: the Form
constructor takes no argument, and the Window
constructor takes an
optional parent argument.
The signature of the final constructor will be:
New MyForm(FirstArg As String, SecondArg As Integer, Optional Parent As Control, Optional ThirdArg As Integer)
In a more general way, the order of arguments for a three level inheritance tree is:
- Mandatory arguments of the grand-parent constructor.
- Mandatory arguments of the parent constructor.
- Mandatory arguments of the final constructor.
- Optional arguments of the grand-parent constructor.
- Optional arguments of the parent constructor.
- Optional arguments of the final constructor.
3.5. Symbol Overriding
When a symbol is overriden, the signature of the symbol in the child class
must be the same as the signature of the symbol in the parent class.
The rules are:
- A dynamic symbol must be overriden by a dynamic symbol, a static one by a static one.
- A method must be overriden by a method with exactly the same signature (same arguments datatypes, same return value datatype if any).
- A read/write property must be overriden by a read/write property with the same datatype.
- A read-only property must be overriden by a read-only property with the same datatype.
- A constant can be overridden by a constant with the same datatype.
are external shared libraries written in C, C++ or in Gambas
that add new functions and/or classes to the Gambas
are grouped according to the component they come from.
4.1. Default internal component
The interpreter includes an internal component named gb
that defines all standard classes of the language.
This component is always loaded by default, and can be considered as part of the language.
4.2. Symbol tables
Each component has its own private class symbol table, so that class names do not conflict.
4.3. Global symbol table
So that components can work together, there is a global symbol table, where all classes exported by components and all classes exported by the current project are stored.
If there is a name conflict in this global symbol table, the last loaded class overrides the
previous loaded class with the same
name, by using inheritance. In other words, the overriding class extends the overriden one.
This last feature can be used for:
- Extending an already declared class by adding new methods or properties to it. For example, the gb.qt Application class reimplements the gb Application class.
- Overriding the methods of an already declared class. For example, the gb.form.dialog component replaces most of the static methods of the Dialog class.
4.4. Project symbol table
Your project has its own private symbol, like any component
, and can export any of its classes to the global symbol table
by using the EXPORT
The project classes are loaded after all components. So your exported class
can override any exported classes declared in any component