faq | docs | tutorials | guide | reference | contact | home  

TUTORIAL - OBJECTS Previous | Next | Tutorial Home

FGL supports standard and enhanced objected-oriented methodologies. In general, classes represent container definitions that can include any combination of data and (typically) related functions within a single entity. Objects are specific instances of defined classes. For example, a class entitled “dogs” may have object instances of “beagle”, “shih-tzu”, and “poodle”. In turn, the class “dogs” may be a subclass of “animal”.

Objects and Classes can contain data, functions, or both. Likewise, FGL supports a number of advanced objected oriented programming (OOP) concepts that include visibility, scope, polymorphism, and inheritance.

Simple Data Object example:
<[
    // define the class
    CLASS objDOG
        local name, breed, sex, age, color, size
    END
]>
<html>
<head>
 <title>Simple object example</title>
</head>
<body text=black bgcolor=white>
<[
    // create an object instance of the objDOG class
    dog = new( "objDOG" )	
    
    // assign values to the dog object
    dog.name = "Cosmo"
    dog.breed = "shih-tzu"
    dog.sex = "M"
    dog.age = 2
    dog.color = "black and white"
    dog.size = "small"
    
    // now use the object data
    ! "The dog is a " + dog.breed + " and " + ( upper( dog.sex ) == "M" ? "his" : "her" )
    ! " name is " + dog.name + ", which is a " + dog.size + " dog. "
    ! dog.name + " is " + dog.color + " and is " + dog.age + " year(s) old."
]>
</body>
</html>

Objects and classes make it very easy to create containers of related information and the processes that work on the information. In the following example, the objContact class contains a number of public variables: fname, lname, street, city, state, zip, and country. PUBLIC variables in a class are accessible outside of the class. Variables with the PRIVATE designation are only available within the class. The object also includes several ACCESS variables, including: fullname and MailingLabel. Access variables are treated the same as public variables outside of the class, however inside the class the are treated as virtual variables whose values are determined based on the instructions associated with the access variable definition. For example:

Object example with access variables:
<[
    CLASS objContact
      PUBLIC:
        local fname, lname, street, city, state, zip, country
        
        ACCESS fullname
            return( self.fname + " " + self.lname )
        END
        
        ACCESS MailingLabel
            local str=""
            
            str += ::fullname + "<br>"
            str += ::street + "<br>"
            str += ::city + ", " + ::state + " " + ::zip + "<br>"
            str += ::country
            
            return( str )
        END
    END
]>
<html>
<head>
 <title>Object example</title>
</head>
<body text=black bgcolor=white>
<[
    contact = new( "objContact" )	
    
    contact.fname = "Angela"
    contact.lname = "Repetti"
    contact.street = "600 N Pine Island Rd, Suite 350"
    contact.city = "Plantation"
    contact.state = "FL"
    contact.zip = "33324"
    contact.country = "USA"
    
    ! contact.fullname + "<br><br>"
    ! contact.MailingLabel
]>
</body>
</html>

Note the use of “self” and “::” operators in the prior example. Both are used to reference data, access variables, and methods within the class and are designated as “self” (similar to the JavaScript "this" reference) regardless of the notation. You may use either one interchangeably, however "::" is two characters less typing than "self".

Objects can also include embedded functions, known as METHODS. These operate much the same way as functions, but have full access to all of the data, access variables, and other methods within the class. The NEW method is a special method which is automatically called whenever an object instance of a class is created. This gives the object the opportunity to initialize or perform any required setup or configuration before it is used.

Advanced object example with methods:
<[
    CLASS objDOG
        local name, breed, sex, age, color, size
        
        METHOD new( a )
            // make sure data is passed in as an array
            // otherwise create a default "empty string" array
            a = type( a ) == "A" ? a : { "", "", "", "", "", "" }
            ::name = a[1]
            ::breed = a[2]
            ::sex = a[3]
            ::age = a[4]
            ::color = a[5]
            ::size = a[6]
            return( 1 )
        END
    END
    
    CLASS MyDogList
        local aData
        
        METHOD new( )
            ::init( )
            return( 1 )
        END
        
        METHOD init( )
            local a, cnt, i
            
            a = ::aRawData
            asort( a, 0, 1 )
            
            cnt = len( a )
            for ( i=1; i<=cnt; i++ )
                ::aData[i] = new( "objDog", a[i] )
            end
            
            return( 1 )
        END
        
        ACCESS aRawData
            static a = {
                { "Cosmo", "shih-tzu", "M", 2, "black and white", "small" },
                { "Merlin", "beagle", "M", 15, "black, white, and brown", "medium" },
                { "Hoss", "Kentucky-dog", "M", 4, "white", "small" },
                { "Elvis", "hound dog", "M", 2, "brown and white", "large" },
                { "Pixie", "teacup yorkie", "F", 1, "brown and grey", "very small" },
                { "MindyLou", "pomeranian", "F", 1, "brown and grey", "very small" }
            }
            return( a )
        END
        
        ACCESS HowManyDogs
            return( len( ::adata ) )
        END
        
        METHOD NameMyDogs( )
            local cnt, i, str="", obj
            
            cnt = ::HowManyDogs
            for ( i=1; i<=cnt; i++ )
                obj = ::aData[i]
                str += obj.name + "<i>: the " + obj.color + " "  + obj.breed + ".</i><br>"
            end
            
            return( str )
        END
        
        ACCESS AverageAge
            local cnt, i, ttl=0
            
            cnt = ::HowManyDogs
            for ( i=1; i<=cnt; i++ )
                ttl += ::aData[i].age
            end
            
            return( int( ttl / cnt ) )
        END
        
    END
    
]>
<html>
<head>
 <title>Advanced object example with methods</title>
</head>
<body text=black bgcolor=white>
<[
    mydogs = new( "MyDogList" )
    
    ! "I have " + mydogs.HowManyDogs + " dogs.<br><br>"
    ! "Their names are:<br>"
    ! mydogs.NameMyDogs( ) + "<br>"
    ! "Their average age is " + mydogs.AverageAge + " years old."
]>
</body>
</html>

In the above example, an object instance of the “MyDogList” class is created. This automatically calls the NEW method within the class which in turn calls the “::init( )” method. The init method creates multiple instances of the “objDog” class from a data array within the class and stores them in an array of objects (::aData) within the MyDogList object. Note that when the objDog objects are created the data is also passed as a parameter (in the form of a multi-dimensional array) to the NEW method of each objDog object.

FGL includes internally predefined engine classes, such as the session object, as well as externalized FGL libraries containing functions and class definitions. The SYSTEM.FLB library includes a large collection of useful functions and classes that can be incorporated into your program by referencing the library. The source code for SYSTEM.FLB is also available.

Object example using libraries:
<[
    LIBRARY \fgl\libs\system.flb
    
    session = new( "session" )    // internal class
    html = new( "objHTML" )       // system.flb class
]>
<html>
<head>
 <title>Object example using libraries</title>
</head>
<body text=black bgcolor=white>
<[
    ! html.notice( "HTTP Header Data:", session.data( "ALL_HTTP" ) )
]>
</body>
</html>

FGL classes provide support for ACCESS and ASSIGN methods for use in the creation and interaction of virtual variables. Virtual variables look and act just like any other class variable outside of the class, however inside the class the ACCESS method is used to get the value of the virtual variable and the ASSIGN method is used to set the value.

Additionally, FGL classes support default handlers for ACCESS and ASSIGN variables as well as for METHODS themselves. If defined within a class, these are called when a variable or method is referenced that otherwise does not exist.

FGL classes also support operator overloading, which is useful for creating extremely advanced and customized classes and object interaction. Operator overloading lets you define how the object behaves during operations, such as addition, subtraction, multiplication, and more.

Advanced object example using inheritance, default handlers, and overloading:
<[
    LIBRARY \fgl\libs\system.flb
    
    CLASS objDefaultExample
      PUBLIC:      
        INHERIT objFromArray
        
        METHOD new( a )
            ::a = a
            return( 1 )
        END
        
        OPERATOR + ( var )
            switch ( type( var ) )
              case "O"
                return( ::fname + " and " + var.fname + " forever" )
              case "C"
                return( ::fname + " and " + var + " forever" )
              default
                return( "unknown handler" )
            end
        END
    END
    
    aAngie = {
        { "fname", "Angie" },
        { "lname", "Repetti" },
        { "title", "Director of Operations" },
        { "phone", "555-473-6868" }
    }
    
    aSteve = {
        { "fname", "Steve" },
        { "lname", "Repetti" },
        { "title", "CEO/Chief Technical Officer" },
        { "phone", "555-473-6868" }
    }
    
    obj1 = new( "objDefaultExample", aAngie )
    obj2 = new( "objDefaultExample", aSteve )
]>
<html>
<head>
 <title>Advanced object example using inheritance, default handlers, & overloading</title>
</head>
<body text=black bgcolor=white>
<[
    ! obj1.fname + " " + obj1.lname + "<br>"
    ! obj1.title + "<br>"
    ! obj1.phone
    ! "<br><br>"
    
    ! obj2.fname + " " + obj2.lname + "<br>"
    ! obj2.title + "<br>"
    ! obj2.phone
    ! "<br><br>"
    
    ! obj1 + obj2 + "<br>"
    ! obj1 + ( obj2.fname + " " + obj2.lname ) + "<br>"
]>
</body>
</html>

In the above example, a minimal class “objDefaultExample” is defined that includes a single INHERIT statement, NEW method, and OPERATOR overload handler. The INHERIT statement causes all of the components of the “objFromArray” class to be available from with the objDefaultExample object. The objFromArray class is defined in the SYSTEM.FLB library with source provided in the OBJECT.FGL file.

The objFromArray class essentially provides a virtual class wrapper around a two-dimensional array of name/value pair data. This is accomplished by using the default ACCESS and ASSIGN methods within the objFromArray class to handle interaction with the data.

The NEW method in the objDefaultExample class is passed the two-dimensional array to a variable identified as “::a”. This is not in the class itself, but is inherited from the objFromArray. This in turn is an ASSIGN method that takes the array, sorts it, and stores it within the class.

The OPERATOR overload handler for the addition operator (+) allows the objects to be added together in unique ways. Furthermore, this handler uses the type( ) function to determine the type of data being added so that it behaves differently depending on whether a string was added or another object.

Obviously this is a rather single-purposed example that would require additional error handling for the various combinations of information that could be processed.

#####