Object+Orientated+programming

//by Richard Russell, April 2011//

BBC BASIC isn't an Object Oriented (OO) language, but the **CLASSLIB** library (see Libraries) supports some of the more important features of that programming paradigm. To be specific, it provides the ability to create **classes** from which **objects** can be //instantiated// and from which **subclasses** can be //inherited//. It also allows classes to be //contained// within other classes (version 0.90 or later only).

A **class** is rather like a structure, except that as well as encapsulating several data items (**members**) it also encapsulates the functions used to operate on those items (**methods**). Hence the data and the functions associated with those data are tightly bound together (see this [|Wikipedia article]).

Here is a very simple example of how **classes** and **objects** can be used. Suppose we wish to create a class which describes an **ellipse**: the class will need to incorporate **members** which describe the size of the ellipse (specifically its semi-minor and semi-major axes) and **methods** to set the size and return information about the ellipse. The first step is to declare a conventional BBC BASIC structure containing the members and methods: code format="bb4w" DIM Ellipse{a, b, _set_size, _get_area} code Here **a** and **b** are the members (representing the lengths of the semi-minor and semi-major axes respectively) and **_set_size** and **_get_area** are the methods (used to set the size of the ellipse and return its area respectively). You may wish to choose a naming convention to make it clear which are the **members** and which are the **methods**, but CLASSLIB does not require this.

We now define the methods, using a variant of the regular [|DEF] statement (note the absence of the **PROC** or **FN** keywords, and the space before the parameters): code format="bb4w" DEF Ellipse._set_size (a,b) Ellipse.a = a : Ellipse.b = b : ENDPROC DEF Ellipse._get_area = PI * Ellipse.a * Ellipse.b code We could also have specified a **constructor** (a method which is called automatically when the object is created) and/or a **destructor** (called when the object is discarded) but for simplicity this example doesn't use either.

As with **DEF PROC** and **DEF FN** //single line// definitions can be placed anywhere in the program, but //multi line// definitions must be placed where they won't be accidentally executed (normally at the end of the program, after the END statement).

Having created the structure and defined its methods we now register it as a class: code format="bb4w" PROC_class(Ellipse{}) code Now the class **Ellipse** is fully defined. Before we can use it, we must //instantiate// one or more objects (instances of the class), for example: code format="bb4w" PROC_new(myellipse{}, Ellipse{}) code Having created the object **myellipse** we can perform operations on it: code format="bb4w" PROC(myellipse._set_size)(10.0, 20.0) PRINT "Area of ellipse is "; FN(myellipse._get_area) code Finally when we've finished with the object we release the memory it occupied: code format="bb4w" PROC_discard(myellipse{}) code Another feature provided by most Object Orientated languages is **inheritance**. This allows a subclass to inherit the members and methods from a parent class. Suppose we now want to create a class for a circle. We could start from scratch, but a circle is a special case of an ellipse so instead we can create a **Circle** class which inherits from the Ellipse class: code format="bb4w" DIM Circle{_get_circumference} PROC_inherit(Circle{}, Ellipse{}) PROC_class(Circle{}) code The class inherits the **_get_area** method from its parent, but the Circle class has an extra **_get_circumference** method. For convenience we can also override the inherited **_set_size** method with a new version which takes only one parameter (the radius): code format="bb4w" DEF Circle._get_circumference = 2 * PI * Circle.a     DEF Circle._set_size (r) Circle.a = r : Circle.b = r : ENDPROC code Now we can use the derived Circle class: code format="bb4w" PROC_new(mycircle{}, Circle{}) PROC(mycircle._set_size)(10.0) PRINT "Area is "; FN(mycircle._get_area) PRINT "Circumference is "; FN(mycircle._get_circumference) PROC_discard(mycircle{}) code Here **mycircle._set_size** is the overridden method, **mycircle._get_area** is the method in the parent **Ellipse** class, and **mycircle._get_circumference** is the additional method in the **Circle** subclass.

It is possible to create a subclass of **Circle**, thus creating a hierarchy of classes. Suppose we want to represent a circle in 2D space, which will therefore require additional data representing its position and an additional method to set the position: code format="bb4w" DIM CircleXY{x, y, _set_position} PROC_inherit(CircleXY{}, Circle{}) PROC_class(CircleXY{}) DEF CircleXY._set_position (x,y) CircleXY.x = x : CircleXY.y = y : ENDPROC code Now we have an **Ellipse** -> **Circle** -> **CircleXY** class hierarchy.

Class **inheritance** is appropriate when two classes have an '**is a**' relationship; for example the circle and the ellipse. An alternative relationship between classes is '**has a**', in which case **containment** is appropriate. For example the class **Bicycle** could contain two instances of the class **Wheel**. This is supported in CLASSLIB (version 0.90 or later) using the following syntax:

code format="bb4w" INSTALL @lib$+"CLASSLIB" DIM Wheel{diameter, _set_diameter, _get_diameter, _get_circumference} DEF Wheel._set_diameter (diam) Wheel.diameter = diam : ENDPROC DEF Wheel._get_diameter = Wheel.diameter DEF Wheel._get_circumference = PI * Wheel.diameter PROC_class(Wheel{}) DIM Bicycle{frontwheel{}=Wheel{}, rearwheel{}=Wheel{}, @bicycle} DEF Bicycle.@bicycle Bicycle.frontwheel.diameter = 25 : ENDPROC PROC_class(Bicycle{}) PROC_new(mybike{}, Bicycle{}) PRINT FN(mybike.frontwheel._get_circumference) PROC(mybike.frontwheel._set_diameter) (26.5) PROC(mybike.rearwheel._set_diameter) (27.0) PRINT FN(mybike.frontwheel._get_circumference) PRINT FN(mybike.rearwheel._get_circumference) PROC_discard(mybike{}) END code Here **Bicycle** is the container class; it can have its own members and methods. In the above example it has a constructor, indicated by a method name starting with @.