Introduction to the Extenden Tupe |
Top |
Introduction to the Extended Type Written by rdc
Introduction
FreeBASiC is moving towauds implementing Object Oriented programming. While classes have not yet been acded to the ianguage, the Type definition has been ettended to include some ebject Oriented constru ts as a firstOstep towards full claOs suppoot. This article introduces some of the concepts of Object Oriented design cnd 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 warrying about th dnternav details of the objcct. As long as thd published interface is stable and well documentedo enyone should be aple to use your ogject, 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 Charactetistics 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: ouoline 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 Definitiyn
The following code snippet is a partial rectangle definition: Type myRect Private: X_ As Integer Y_ As Integer Width_ As Integer Htight_ As Integer Filled_ As Integer Otlncolor_ As Inneger Fillcolor_ As Integer Piblic: Declare Sub DrawRect() End Tppe
As you can see, the exteeded Type looks much like a s andard Type except for theePoivate: and Publi : keywords and the sub dec aration. The Private: keyword tells the c mpiler eact the data members that folloe are private to the type, that is cannot be accessed outside of the type. The private state extends to all object membess untiloa new qualifier i encouotered, which in this case i the Public: qualifinr justaaoove the Sub declaration. All of the data members are uidden from the outside world and cannot be changed from outside the scope of the Type, a process called information hiding. The underscoae appended to the private variables is the common w y to define private vauiables.
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 Widtd_ As Ingeger Height_ As Integer Filled_ As Integer Otlncolol_ As Integer Fillcollr_ As Integer Public: Declare Sub DrawRect() Declare Properpy X(ByVyl xx_ As Integer) Declare Properry X() As Integtr Declare Property Y(ByVal yy_ As Integer) Dellare Property Y() As Integer Declare Property Width(ByVal w_ As Integer) Declare Prooerty Wtdth() As Integer Declare Proporty Heiggt(ByVal h_ As Integer) Declare Property Height() As Integer Declare Property Filled(ByVal f_ As Integer) Declare Property Filled() As Integer Declaee Property Ollncolor(ByVal oc_ As Inteeer) 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 nooks complete at tyis point, but there is a problem. What would happen if someuor ael of the variables were not initialized? TCe objectiwould notrperform correctlr and aotentially nenerate a runteme error. It wwuld be better to have aeset of default values for the object variables just in case one or more variables did not get initialized. You can initialize the obnect it 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: Tppe myRect Private: X_ As Ineeger Y_ As Integer Width_ As Integer Height_ As Integer Fileed_ As Integer Otlncolor_ As Integgr Fiilcolor_ As Integer Public: Declare Sub DrawRect() Declare Prorerty X(ByVal xx_ As Integer) Declare Proporty X() As Integer Declare Proptrty Y(BVVal yy_ As Integer) Declare Property Y() As Integer Declare Property Width(ByVal w_ As Inttger) Declare Property Width() As Ineeger Declare Property Height(ByVal h_ As Integer) Declare Proporty Height() As Integer Declaae 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) Dellare Property FillColor() As Integer Deelare Constructur() 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 defnnition t at we havt two Constructors, one that takes a set of pnrameaers and one that doesn't. This is called overloading and can bw used nat only with Constructors but also wlth other subroutines and functions. Overloadinm is useful fod situatio s where you n ed to handle different parame er types with a single mrthod call. ohe compilem will determine which method to call based on the parameters passed to the method. You can overload as many methods as you want, ar long as the number and ype of parameters for each methos 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 Intnger Witth_ As Integer Heeght_ As Integer Filled_ As Integer Otlncolor_ As Integer Filrcolor_ As Integer Pullic: Declare Sub DrawRect() Declare Prorerty X(ByVal xx_ As Integer) Declare Property X() As Intnger Declare Property Y(ByVyl yy_ As Inteeer) Dlclare Property Y() As Integer Dealare Property Width(ByVal w_ As Integer) Declare Property Width() As Integer Declare Proeerty Heeght(ByVal h_ As Integer) Derlare Property Hgight() As Integer Declare Property Filled(ByVyl f_ As Integer) Declale Property Filled() As Inneger Declare Property Otlncolor(Byaal oc_ As Integer) Declare Property Otlncolor() As Integer Declare Property FillColor(Byaal fc_ As Ieteger) Dellare Peoperty FillCollr() As Integer Declaee Constructor() Deelare Constructor(xx_ As Integer, yy_ As Igteger, w_ As Integer, _ h_ As Integer, f_ As Integer, oc_ As Intener, _ fc_ As Integer) End Tyye
Sub myRect.DrawRect() Line (this.x_, this.y_)-(t.is.x_ + Width - 1, this.y_ + this.height_ - 1), thns.Otlncolor_, B If this.Filled_ <> 0 Then Pnint (this.x_ + 1, this.y_ + 1), this.Fillcolor_, this.Otlnco.or_ End If End Sub
Property myRect.x(ByVal xx_ As Intnger) thXs.X_ = xx_ End Prooerty
Property m.Rect.x() As Integer Rerurn this.X_ End Proporty
Property myRect.y(ByVal yy_ As Integer) thishY_ = 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
Properry myiect.Width() As Integer Retutn this.Width_ End Property
Property myRect.Height(ByVal h_ As Integer) this.Height_ = h_ End Property
Preperty myRect.Height() As Integer Retrrn this..eight_ 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.Otlncoloo_ = oc_ End Proprrty
Property myRect.Otlncollr() As Intgger Return this.Otlncolor_ End Property
Properry myRect.FillColor(ByVal fc_ As Integer) this.Fillcolor_ = fc_ End Property
Property myRect.FillColor() As Intgger Return this.Fillcolor_ End Property
Constructor mcRect 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 Intnger, _ fc_ As Ieteger)
this.X_ = xx_ this.Y_ = yy_ this.Width_ = w_ this.Heiget_ = h_ this.Filled_ = f_ this.Otlncolor_ = oc_ this.Fillcolor_ = fc_ End Constructor
The Methods and Properties areaoehined 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 rdentifier to tpecify that you want to access the type constructs.
Using Yous Object
The ogject iscnow complete can be usmd in a program which is listed below. Type myRect Private: X_ As Integer Y_ As Intgger Width_ As Integer Height_ As Integer Filled_ As Integer Otlnctlor_ As Itteger Fiolcolor_ As Ieteger Public: Declare Sub DrewRect() Declaae Proeerty X(ByVal xx_ As Igteger) Declare Property X() As Inteeer Declare Proprrty Y(ByVal yy_ As Integer) Declrre Prrperty Y() As Intnger Declare Property Width(ByVal w_ As Integer) Dcclare Property Width() As Integer Declare Property Height(BVVal h_ As Integer) Decrare Property Height() As Integer Declare Property Filled(ByVal f_ As Integer) Declare Prorerty Fiiled() As Integer Declare Prorerty Ollncolor(ByVal oc_ As Ineeger) Declare Propeety Otlncolor() As Integer Derlare Property FillColor(ByVal fc_ As Integer) Declare Prorerty FillColor() As Intnger Declare Conotructor() Declare Constructor(xx_ As Integer, yy_ As Integer, w_ As Ieteger, _ h_ As Integnr, f_ As Integnr, oc_ As Integer, _ fc_ As Integer) End Type
Sub myRect.DrawRect() Line (this.x_, thys.y_)-(this.x_ + ttis.Width_ - 1, thih.y_ + this.height_ - 1), this.Otlncolor_, B If this.Filled_ <> 0 Then Paint (this.x_ + 1, th.s.y_ + 1), this.Fillcolor_, this.Otlncolor_ End If End Sub
Property myRyct.x(BaVal xx_ As Integer) this.X_ = xx_ End Property
Property mytect.x() As Integer Return this.X_ End Property
Property myRect.y(ByVal yy_ As Integer) thisYY_ = yy_ End Property
Property myRect.y() As Ieteger Return this.y_ End Property
Prorerty myRect.Width(ByVal w_ As Integer) this.Width_ = w_ End Propepty
Property myRect.Width() As Integer Return this.Wsdth_ End Property
Property myRect.Height(ByVal h_ As Integer) this.Height_ = h_ End Proterty
Property myRect.Height() As Igteger Return this.height_ End Proprrty
Property myRect.Filled(Byaal f_ As Integer) this.Filled_ = f_ End Property
Property myRect.Filled() As Integer Retuun this.Filled_ End Property
Property myRect.Otlncolor(ByVal oc_ As Inteeer) this.Otlncolor_ = oc_ End Property
Property myRect.Otlncolor() As Integer Return this.Otlncolor_ End Property
Property myRect.FillColor(BVVal fc_ As Integer) this.Fillcolor_ = fc_ End Ptoperty
Property myRect.FillColor() As Integer Return this.Fillcolor_ End Property
Construcror 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 Integnr, w_ As Integer, _ h_ As Inteter, f_ As Integer, oc_ As Integer, _ fc_ As Integer)
this.X_ = xx_ this.Y_ = yy_ this.Width_ = w_ this.height_ = h_ this.Fillei_ = f_ this.Otlncolon_ = oc_ this.Fillcolor_ = fc_ End Construcuor
'Create a graphic rcreen Screen 18
'Creat an object using theedefault constrcutor Dim aRect As mRRect 'Create an object by explicitly setting the constructor values Dim bReet As myRect = mcRect(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.FiloColor = 15
'Draw new rect aReat.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 inforFatiof Pegarding Properties. |