Chapter 9. Tutorial III

9.1. Classes and OOP

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();
    }
    	  

Copyright 1995-2002 by Cogent Real-Time Systems, Inc.