Introduction to the Extended Type

Written by rdc

 Introduction

FreeBASIC is moving towards implementing Object Oriented programming. While 
classes have not yet been added to the language, the Type definition has 
been extended to include some Object Oriented constructs as a first step 
towards full class support. This article introduces some of the concepts of 
Object Oriented design and explains some of the extended type constructs.

 Object Oriented Programming

Object Oriented Programming, usually shortened to OOP, is a methodology 
that enables the programmer to build code units called objects. An object 
is a thing; it is a unit of code that represents something that needs to be 
manipulated in a program. You can think of an object as a noun: a person, 
place or thing. An object could be a sprite, a drawing primitive or 
something more elaborate like a tank in a game. Any concrete entity that 
has a set of characteristics and actions can be represented as an object.

An object contains both the data needed by the object, and the methods 
(subroutines and functions) that act on the data. This grouping of data and 
methods into a single entity is called encapsulation. Encapsulation allows 
you to create modular units that can be reused in multiple programs. This 
idea of code reuse was the main motivation in the creation of the OOP 
paradigm.

Another beneficial consequence of encapsulation is information hiding. The 
data inside the object is shielded from the outside world so that unwanted 
changes to the data cannot occur. Instead of accessing a variable directly, 
the object has a public interface that the external program should use to 
access and change data members. By using an interface, you can control how 
the object behaves and ensure that its operation is consistent across many 
programs. 

The interface also allows you to make internal changes to the code, without 
changing the way the object is accessed. As long as you don't change the 
published interface, that is change any existing public methods, you can 
improve the object without breaking any existing code that relies on the 
object. In the cases where a program my need an improved method, you can 
leave the old method in place to maintain compatibility, and just add a new 
method with the improved functionality. New programs can use the new 
method, while old programs can still use the old method.

Another advantage of using a public interface is so that other programmers 
can use your object without worrying about the internal details of the 
object. As long as the published interface is stable and well documented, 
anyone should be able to use your object, even beginners.

 The Published Contract

As already stated, OOP was designed to enable code reuse among programmers. 
In order for code reuse to be helpful, the published interface must remain 
stable. That is, once an object has been released and is being used in 
programs, the published interface should not change so that programs that 
use the object continue to work correctly. There is an implicit contract 
between you as the author of the object and the end-user of your object 
that you will maintain the published interface across changes that may need 
to be made to the object. This implicit contract between author and user is 
the main strength of the OOP paradigm, and is the main reason that OOP has 
become such a powerful programming methodology.

 The Characteristics of an Object

As already mentioned, an object contains both data and methods. The data 
describes the properties of an object, while the methods describe what the 
object can do. A simple, and not-really-useful example will illustrate this 
concept. 

Suppose you want to create an object that draws a rectangle on the screen. 
A rectangle can have several properties that would be contained within the 
data members of the object. A rectangle has an origin on the screen, 
normally the top left corner, which can be represented by x and y data 
members. A rectangle has a width and a height, so the object would have 
width and height data members. A rectangle can either be outlined or 
filled, so a filled flag data member can be added to the object. Of course, 
if you are going to draw a rectangle, you will want to draw it in a 
particular color, so the object will need to have a color data member, and 
to have the object be a bit more flexible, you can add a color member for 
the outline and a different color member for the fill. Of course you will 
need a method to actually draw the rectangle on the screen, so you can add 
a draw routine to the object definition.

So our rectangle object has the following preliminary properties and 
methods:

    Property: x and y origin
    Property: width
    Property: height
    Property: filled
    Property: outline color
    Property: fill color
    Method: DrawRect

This list is called the object definition. In FreeBASIC you define an 
object using the extended Type definition. The extended Type is similar to 
the standard Type, with some added language constructs that implements a 
subset of OOP features.

 A Rectangle Type Definition

The following code snippet is a partial rectangle definition:
   Type myRect
     Private:
      X_ As Integer
      Y_ As Integer
      Width_ As Integer
      Height_ As Integer
      Filled_ As Integer
      Otlncolor_ As Integer
      Fillcolor_ As Integer
      Public:
      Declare Sub DrawRect()
   End Type

As you can see, the extended Type looks much like a standard Type except 
for the Private: and Public: keywords and the sub declaration. The Private: 
keyword tells the compiler that the data members that follow are private to 
the type, that is cannot be accessed outside of the type. The private state 
extends to all object members until a new qualifier is encountered, which 
in this case is the Public: qualifier just above the Sub declaration. All 
of the data members are hidden from the outside world and cannot be changed 
from outside the scope of the Type, a process called information hiding. 
The underscore appended to the private variables is the common way to 
define private variables.

Information hiding is a way to maintain the integrity of the object. You 
should never allow an outside process to directly access a data member. All 
data access should be through the use of Property members so that you can 
control what is being passed to your object. Strict control over your 
object's data will help prevent many errors that may occur when a 
programmer uses your object.
   Type myRect
     Private:
      X_ As Integer
      Y_ As Integer
      Width_ As Integer
      Height_ As Integer
      Filled_ As Integer
      Otlncolor_ As Integer
      Fillcolor_ As Integer
      Public:
      Declare Sub DrawRect()
      Declare Property X(ByVal xx_ As Integer)
      Declare Property X() As Integer
      Declare Property Y(ByVal yy_ As Integer)
      Declare Property Y() As Integer
      Declare Property Width(ByVal w_ As Integer)
      Declare Property Width() As Integer
      Declare Property Height(ByVal h_ As Integer)
      Declare Property Height() As Integer
      Declare Property Filled(ByVal f_ As Integer)
      Declare Property Filled() As Integer
      Declare Property Otlncolor(ByVal oc_ As Integer)
      Declare Property Otlncolor() As Integer
      Declare Property FillColor(ByVal fc_ As Integer)
      Declare Property FillColor() As Integer
   End Type

The Declare statements following the Public: qualifier comprises the public 
interface to your object. Since the variables of the type are defined with 
the Private: keyword, the only way to access the variables is through the 
Property members maintaining the integrity of the object. Since you define 
the code in each Property member, you have full control over what is being 
put into your object. A common example of this is to put range checking 
code in your property members so that the object does not contain invalid 
data.

In this example, the variables can be both written and read. The compiler 
distinguishes between a read Property and a write Property by the type of 
the method. A subroutine-formatted Property is a write property since you 
are passing a value that will be saved in a private variable. A 
function-formatted Property is a read property since a private variable 
will be returned to the caller. You can create read-only Properties by 
adding just a function-formatted Property or write-only Properties by just 
adding a subroutine-formatted Property.

 Creating Well-Behaved Objects

The definition looks complete at this point, but there is a problem. What 
would happen if some or all of the variables were not initialized? The 
object would not perform correctly and potentially generate a runtime 
error. It would be better to have a set of default values for the object 
variables just in case one or more variables did not get initialized. You 
can initialize the object at the moment of creation by using a Constructor.

A Constructor is a subroutine that is called when the object is created 
using the Dim (or New) statement. Constructors are useful for initializing 
an object, either with default values, or values you pass to the 
Constructor. The updated type definition now looks like the following:
   Type myRect
     Private:
      X_ As Integer
      Y_ As Integer
      Width_ As Integer
      Height_ As Integer
      Filled_ As Integer
      Otlncolor_ As Integer
      Fillcolor_ As Integer
      Public:
      Declare Sub DrawRect()
      Declare Property X(ByVal xx_ As Integer)
      Declare Property X() As Integer
      Declare Property Y(ByVal yy_ As Integer)
      Declare Property Y() As Integer
      Declare Property Width(ByVal w_ As Integer)
      Declare Property Width() As Integer
      Declare Property Height(ByVal h_ As Integer)
      Declare Property Height() As Integer
      Declare Property Filled(ByVal f_ As Integer)
      Declare Property Filled() As Integer
      Declare Property Otlncolor(ByVal oc_ As Integer)
      Declare Property Otlncolor() As Integer
      Declare Property FillColor(ByVal fc_ As Integer)
      Declare Property FillColor() As Integer
      Declare Constructor()
      Declare Constructor(xx_ As Integer, yy_ As Integer, w_ As Integer, _
                     h_ As Integer, f_ As Integer, oc_ As Integer, _
                     fc_ As Integer)
                     
   End Type

You will notice in the definition that we have two Constructors, one that 
takes a set of parameters and one that doesn't. This is called overloading 
and can be used not only with Constructors but also with other subroutines 
and functions. Overloading is useful for situations where you need to 
handle different parameter types with a single method call. The compiler 
will determine which method to call based on the parameters passed to the 
method. You can overload as many methods as you want, as long as the number 
and type of parameters for each method is unique.

In this instance, if the Constructor is not passed any parameter values, it 
will initialize the variables to a set of default values. If the 
Constructor is called with parameters, then it will use the passed values 
to initialize the object's variables.

There is also a Destructor method that is called when the object is 
destroyed. You can use the Destructor to perform any cleanup tasks that 
must be carried out before the object is released from memory. If the 
object created any pointer references, or opened any files, then you would 
clean up those references in the Destructor. Since the Rectangle object 
doesn't create any outside references, a Destructor is not needed.

 Filling in the Object Methods

The type definition is a template for the object type and tells the 
compiler how to set up the object in memory. However, in order to actually 
use the object, you need to create the actual method calls, which is shown 
in the next listing.
   Type myRect
     Private:
      X_ As Integer
      Y_ As Integer
      Width_ As Integer
      Height_ As Integer
      Filled_ As Integer
      Otlncolor_ As Integer
      Fillcolor_ As Integer
      Public:
      Declare Sub DrawRect()
      Declare Property X(ByVal xx_ As Integer)
      Declare Property X() As Integer
      Declare Property Y(ByVal yy_ As Integer)
      Declare Property Y() As Integer
      Declare Property Width(ByVal w_ As Integer)
      Declare Property Width() As Integer
      Declare Property Height(ByVal h_ As Integer)
      Declare Property Height() As Integer
      Declare Property Filled(ByVal f_ As Integer)
      Declare Property Filled() As Integer
      Declare Property Otlncolor(ByVal oc_ As Integer)
      Declare Property Otlncolor() As Integer
      Declare Property FillColor(ByVal fc_ As Integer)
      Declare Property FillColor() As Integer
      Declare Constructor()
      Declare Constructor(xx_ As Integer, yy_ As Integer, w_ As Integer, _
                     h_ As Integer, f_ As Integer, oc_ As Integer, _
                     fc_ As Integer)
   End Type

   Sub myRect.DrawRect()
      Line (this.x_, this.y_)-(this.x_ + Width - 1, this.y_ + this.height_ - 1), this.Otlncolor_, B
      If this.Filled_ <> 0 Then
         Paint (this.x_ + 1, this.y_ + 1), this.Fillcolor_, this.Otlncolor_
      End If   
   End Sub

   Property myRect.x(ByVal xx_ As Integer)
      this.X_ = xx_
   End Property

   Property myRect.x() As Integer
      Return this.X_
   End Property

   Property myRect.y(ByVal yy_ As Integer)
      this.Y_ = yy_
   End Property

   Property myRect.y() As Integer
       Return this.y_
   End Property

   Property myRect.Width(ByVal w_ As Integer)
      this.Width_ = w_
   End Property

   Property myRect.Width() As Integer
      Return this.Width_
   End Property

   Property myRect.Height(ByVal h_ As Integer)
      this.Height_ = h_
   End Property

   Property myRect.Height() As Integer
      Return this.Height_
   End Property

   Property myRect.Filled(ByVal f_ As Integer)
      this.Filled_ = f_
   End Property

   Property myRect.Filled() As Integer
      Return this.Filled_
   End Property

   Property myRect.Otlncolor(ByVal oc_ As Integer)
      this.Otlncolor_ = oc_
   End Property

   Property myRect.Otlncolor() As Integer
      Return this.Otlncolor_
   End Property

   Property myRect.FillColor(ByVal fc_ As Integer)
      this.Fillcolor_ = fc_
   End Property

   Property myRect.FillColor() As Integer
      Return this.Fillcolor_
   End Property

   Constructor myRect
      this.X_ = 0
      this.Y_ = 0
      this.Width_ = 10
      this.Height_ = 10
      this.Filled_ = 0  
      this.Otlncolor_ = 15
      this.Fillcolor_ = 7
   End Constructor

   Constructor MyRect (xx_ As Integer, yy_ As Integer, w_ As Integer, _
                     h_ As Integer, f_ As Integer, oc_ As Integer, _
                     fc_ As Integer)

      this.X_ = xx_
      this.Y_ = yy_
      this.Width_ = w_
      this.Height_ = h_
      this.Filled_ = f_  
      this.Otlncolor_ = oc_
      this.Fillcolor_ = fc_
   End Constructor

The Methods and Properties are defined using the Sub/Function/Property 
TypeName.methodname syntax. This tells the compiler how to match up methods 
with the proper type definition. The Constructors are defined with the type 
name for the same reason. The this identifier is a hidden parameter that is 
passed to the methods that refers to the defined type. You use the this 
identifier to specify that you want to access the type constructs.

 Using Your Object

The object is now complete can be used in a program which is listed below.
   Type myRect
     Private:
      X_ As Integer
      Y_ As Integer
      Width_ As Integer
      Height_ As Integer
      Filled_ As Integer
      Otlncolor_ As Integer
      Fillcolor_ As Integer
      Public:
      Declare Sub DrawRect()
      Declare Property X(ByVal xx_ As Integer)
      Declare Property X() As Integer
      Declare Property Y(ByVal yy_ As Integer)
      Declare Property Y() As Integer
      Declare Property Width(ByVal w_ As Integer)
      Declare Property Width() As Integer
      Declare Property Height(ByVal h_ As Integer)
      Declare Property Height() As Integer
      Declare Property Filled(ByVal f_ As Integer)
      Declare Property Filled() As Integer
      Declare Property Otlncolor(ByVal oc_ As Integer)
      Declare Property Otlncolor() As Integer
      Declare Property FillColor(ByVal fc_ As Integer)
      Declare Property FillColor() As Integer
      Declare Constructor()
      Declare Constructor(xx_ As Integer, yy_ As Integer, w_ As Integer, _
                     h_ As Integer, f_ As Integer, oc_ As Integer, _
                     fc_ As Integer)
   End Type

   Sub myRect.DrawRect()
      Line (this.x_, this.y_)-(this.x_ + this.Width_ - 1, this.y_ + this.height_ - 1), this.Otlncolor_, B
      If this.Filled_ <> 0 Then
         Paint (this.x_ + 1, this.y_ + 1), this.Fillcolor_, this.Otlncolor_
      End If   
   End Sub

   Property myRect.x(ByVal xx_ As Integer)
      this.X_ = xx_
   End Property

   Property myRect.x() As Integer
      Return this.X_
   End Property

   Property myRect.y(ByVal yy_ As Integer)
      this.Y_ = yy_
   End Property

   Property myRect.y() As Integer
       Return this.y_
   End Property

   Property myRect.Width(ByVal w_ As Integer)
      this.Width_ = w_
   End Property

   Property myRect.Width() As Integer
      Return this.Width_
   End Property

   Property myRect.Height(ByVal h_ As Integer)
      this.Height_ = h_
   End Property

   Property myRect.Height() As Integer
      Return this.Height_
   End Property

   Property myRect.Filled(ByVal f_ As Integer)
      this.Filled_ = f_
   End Property

   Property myRect.Filled() As Integer
      Return this.Filled_
   End Property

   Property myRect.Otlncolor(ByVal oc_ As Integer)
      this.Otlncolor_ = oc_
   End Property

   Property myRect.Otlncolor() As Integer
      Return this.Otlncolor_
   End Property

   Property myRect.FillColor(ByVal fc_ As Integer)
      this.Fillcolor_ = fc_
   End Property

   Property myRect.FillColor() As Integer
      Return this.Fillcolor_
   End Property

   Constructor myRect
      this.X_ = 0
      this.Y_ = 0
      this.Width_ = 10
      this.Height_ = 10
      this.Filled_ = 0  
      this.Otlncolor_ = 15
      this.Fillcolor_ = 7
   End Constructor

   Constructor MyRect (xx_ As Integer, yy_ As Integer, w_ As Integer, _
                     h_ As Integer, f_ As Integer, oc_ As Integer, _
                     fc_ As Integer)

      this.X_ = xx_
      this.Y_ = yy_
      this.Width_ = w_
      this.Height_ = h_
      this.Filled_ = f_  
      this.Otlncolor_ = oc_
      this.Fillcolor_ = fc_
   End Constructor

   'Create a graphic screen
   Screen 18

   'Create an object using the default constrcutor
   Dim aRect As myRect
   'Create an object by explicitly setting the constructor values
   Dim bRect As myRect = myRect(200, 200, 200, 100, 1, 15, 9)

   'Draw the rectangles on the screen
   aRect.DrawRect
   bRect.DrawRect

   'Update aRect properties
   aRect.X = 90
   aRect.Y = 20
   aRect.Filled = 1
   aRect.FillColor = 15

   'Draw new rect
   aRect.DrawRect
   Sleep
   End

To initialize the object using the default Constructor, you simply Dim the 
extended Type just as you would the standard type. If the Constructor only 
takes a single value then you can use the Dim var as Typename = value 
syntax. To initialize the object with a set of values, you Dim the type and 
then use the = typename(par1m parm1...) syntax. You can see that accessing 
the members of the object is just like accessing the member of a standard 
type.

Thanks to cha0s at the FreeBASIC forums for the information regarding 
Properties.
