Gamma implements object-oriented programming (OOP) features which provide a single-inheritance class mechanism with instance variables and methods. Since Gamma is an interpreter, the object definitions are truly dynamic, allowing for run-time extensibility. This example provides the simplest of starting points to this key software methodology.
#!/usr/cogent/bin/gamma
/*
* Demonstrates:
* class definitions: attributes and methods.
* constructors and destructors
* method overloading
*/
/*
* Define a class of animal, with no default type and a default of 4 legs
*/
class animal
{
type = "animal";
num_legs = 4; // By default, animals have 4 legs
}
/*
* The constructor for an animal is called when any instance of animal
* or a subclass of animal is created using a call to 'new'. Constructors
* have no arguments.
*/
method animal.constructor()
{
princ ("A ", class_name(class_of(self)), " is born\n");
}
/*
* The destructor for an animal is called when any instance of animal
* or a subclass of animal is deleted by the garbage collector. There
* is no explicit deletion mechanism in Gamma. Destructors have no
* arguments.
*/
method animal.destructor ()
{
princ ("A ", class_name(class_of(self)), " dies\n");
}
/*
* All methods except constructor and destructor are overloaded, meaning
* that only the method for the nearest class in the ancestry of the
* instance will be called for any given method name.
*/
method animal.describe ()
{
princ ("The ", self.type, " has ", self.num_legs, " legs.\n");
}
/*
* Create a subclass of animal of a particular type.
*/
class cat animal
{
type = "feline";
}
/*
* Create another subclass of animal which is itself a parent class
*/
class insect animal
{
num_wings = 2;
num_legs = 6;
}
/*
* Overload the description method for insects so we hear about
* wings and legs when we ask about insects.
*/
method insect.describe ()
{
/*
* We can explicitly call a method of a parent class using the
* 'call' function and naming a parent class.
*/
call (self, #animal, #describe);
princ (" (oh, and ", self.num_wings, " wings)\n");
}
/*
* Create a destructor for an insect. This will be run before the
* animal destructor.
*/
method insect.destructor ()
{
princ ("Crunch. ");
}
/*
* Create a subclass of an insect which is a particular type.
*/
class beetle insect
{
type = "rhinoceros beetle";
num_wings = 4;
}
function main ()
{
local pet = new (cat);
local bug = new (beetle);
/*
* cat gets its describe method from the animal class
*/
pet.describe();
/*
* beetle gets its describe method from the insect class
*/
bug.describe();
/*
* Since the destructor will be implicitly called by the garbage
* collector, we can cause the destructor to occur by removing
* all references to the instances (set the variables referencing
* the instances to nil), and then explicitly invoke the garbage
* collector. Typically this is not necessary, as the garbage
* collector will run when necessary.
*/
pet = nil;
bug = nil;
gc();
}