CHAPTER 11

STRUCTURED PROGRAMMING AND OOP.

INTRODUCTION:

I am introducing this topic before discussing particular Windows programming topics in more detail.

Although the codes I have used to create working programs are not strictly authentic examples of OOP, or Object Oriented Programming, OOP concepts have had a significant influence on the

method I have used. It is important for the reader to be aware, as early as possible, of the thinking that underlies this widely used programming method. This is because some kind of structured approach to programming is necessary in order to organise and control large or complicated programs, as discussed in the following section.

OVERVIEW OF STRUCTURED PROGRAMMING:

Writing program code step by step, as required, will quickly lead the programmer to discover a basic problem as soon as the code starts to become long and complicated. Soon it will begin to turn into a maze of code segments that will be almost impossible to reread and recognise, and then modify, and debug.

A code segment may well be easily readable as it is being written but, if one has to return to it at a later date, when it is no longer fresh in the mind, it can easily become virtually unreadable, necessitating a laborious effort to try to re-understand what it actually means or does. It is therefore imperative to have some kind of regular or formally structured

method of writing code, so that the code will be as easily readable as possible at any later date. Another possible reason for having structured programming is to try to have code that can be modified in one part without necessitating extensive corresponding modifications in many other parts.

This latter consideration is what lies behind the creation of the structured programming method known as OOP, or Object Oriented Programming. This involves the creation of code 'modules', known as 'objects', which are as self-contained and independent as possible with respect to all other, similar code objects.

DATA STRUCTURES AND PROCEDURE STRUCTURES:

We have already encountered one of the most basic elements of OOP type structured programming, and that is the data structure. A data structure associates together a list of variables or parameters that can be relevant to a single software object, like a bitmap.

To fully describe a bitmap requires a list of parameters to determine its width, height, the x and y coordinates of its position on the screen, and the identification number, or handle, given to it by the operating system. Listing all these parameters together in a suitably named manner, most usefully as a single memory block, enables a programmer to easily keep track of all the variables required to describe the bitmap, and which ones are being modified. An example of such a data structure is shown below.

Apart from the data structure, there are also code procedures that are necessary when working with bitmaps, such as creating a bitmap, changing its location, destroying it, setting the bitmap pixel colours, or creating the bitmap header data, and such

a list of procedures can also be given names in a manner that makes them immediately recognisable as bitmap procedures.

Even more usefully, these procedures can be kept together, such as in one include file, so that they form a kind of bitmap procedure list. Although the elements of such a list are not thereby linked together in a manner like the elements of a data structure are linked together as elements in a single memory block, they can be easily, and usefully, thought of as forming a kind of procedure structure, even if this can be criticised as being merely a matter of semantics. Thus, a bitmap procedure 'structure' might appear as something like the following:

BITMAP.CreateBitmap
BITMAP.MoveBitmap
BITMAP.DestroyBitmap
BITMAP.SaveBitmap
etc.

Here, the various bitmap procedures are associated together simply by the design of their individual names. The name BITMAP is included in each of the procedure names, so that the procedure name indicates the procedure 'structure' and 'object' to which it is related. This, together with the rest of the procedure name, is very useful in helping a programmer recognise immediately what a procedure code is for, and what it does.

THE OBJECT STRUCTURE:

If we now associate together the bitmap data structure with the bitmap procedure structure, we can conceive what we might call an 'object' structure. This, in fact, is the basis of object oriented programming, even if it is not always described in this way. The data structure contains the parameters

that define the object, and what I have called the procedure structure is known in object oriented programming as its 'methods'. Here we can see the value of using the concept of a 'structure' to describe the data, its associated procedures, and even the object itself.

ARRAY STRUCTURES AND CLASS IN OOP:

The size of each element in a data structure does not have to be always of the same fixed size for all data structure elements. It is possible for an element to be an array, or memory block, rather than a single memory location. An example is the case where a data structure element has to contain a text string, which is an array of text characters. It is also possible to connect complete data structures together, one after another, within a single memory block. This will create an array of data structures all with successively different offsets from the same initial memory location.

The bitmap data structure shown above, for example, has a total size in memory of 1ch, and is sufficient to contain the dword parameters for a single bitmap. If, now, we create a memory block called, say, BITMAP.ARRAY, and give it a size in memory of 1ch*10, for example, we will have a memory block capable of storing 10 bitmaps, with each bitmap having its data structure of size 1ch, as shown above. A program can now create new bitmaps, as desired, and the memory location of, for example, bitmap no. 3 data structure will be at [BITMAP.ARRAY+1ch*3]. So an entire set of individual bitmaps can be stored together in memory, with any individual one being easily created, retrieved, or destroyed.

The BITMAP.ARRAY is thus what might be called an 'array structure', containing numerous individual bitmap objects, and this can be easily associated with the concept of a CLASS in OOP.

Since a bitmap is a particular type of object, an individual bitmap is seen, in OOP, as a particular 'instance' of the BITMAP CLASS. High Level Languages, like C++ etc., are designed to support instructions that directly express OOP principles. However, as with all HLLs, the instructions give no understanding of the underlying programming details, which are hidden in the compiler. To implement such concepts in Assembly Language,

they have to be formulated at the immediate programming level. So we may have, for example, using the BITMAP CLASS:

Here the procedure structure, or methods, associated with the class, are different from those associated with the object. The bitmap data structure is used for both, and the difference is that the one associated with the class has no definite values, and is used to create a new bitmap, whereas the one associated with a bitmap object will have already existing values, stored in the BITMAP.ARRAY. The methods associated with the class create new bitmap objects, or destroy those that already exist, whereas the methods (only one in this example) associated with the bitmap object implement operations of the object (changing its location), without changing the object itself.

INHERITANCE:

An object may naturally have a particular and also a general description. A motor bike, for example, is a particular description of an object, but a motor bike also has the more general description of vehicle. Thus, if you are dealing with an array of different vehicles, such as motor bikes, cars, trucks, etc., you can create a general vehicle class, as an array structure, in which each type of vehicle has the same elements, but with different values.

Any vehicle, as such, will have fuel, tyres, and a facility for carrying objects, whether people or goods, and will have a location on a road, and so on. The values of these elements will be different for different kinds of vehicles, but the same methods, such as filling the fuel tank, or pumping up the tyres, will be the same for every vehicle, even if the values used

are different. Individual types of vehicle, however, will also have their own unique properties. Motor cycles, for example, are associated with helmets and riding gear, whereas cars and trucks are not. Buses and taxis have paying customers, i.e. fares, but cars and bikes do not, and so on.

Thus, an individual bus will be in the class 'bus' but also in the more general class 'vehicle', and can use the class methods associated with 'vehicle' as well as any extra methods associated with the class 'bus'.

This is called 'inheritance' in OOP. That is, the class 'bus' 'inherits' the methods of the class 'vehicle'. This means that the inherited code doesn't have to be replicated for each particular type of vehicle, thus reducing the size of the overall program code.

ENCAPSULATION AND MESSAGES:

An object, or class concept, in OOP, is used to create what is called encapsulation. That is, the data of an object can be accessible only to its procedure structure functions, or methods, and can thus be protected from being modified by code from outside of its procedure structure, and can thus be seen to be 'hidden' from the outside environment, and becomes a kind of module. The necessary interface between the object structure and the outside code is made to be as small as possible. In general, the outside environment is described as communicating with the object by sending 'messages' to it rather than calling its procedures, so that it can arrange to call its own procedures in response to the message. This is really a conceptual distinction because a message cannot

be sent to an object without calling something belonging to the object. This, however, in the most extreme case, could potentially be only a single 'messages' subroutine, which would be the only subroutine, or function, or method, that could ever be called from the outside coding environment.

This, indeed, is like the Windows messaging system, which sends all messages to the one program entry point in WinMain.

In the above BITMAP CLASS example, we could create a procedure called BITMAP.GetMessage such that all operations on bitmaps must be received by any bitmap through this procedure.

POSSIBLE PROBLEMS WITH OOP ENCAPSULATION:

The argument put forward in this section is not presented as an effort to persuade the reader not to choose OOP as the preferred programming method. Its purpose, instead, is to consider possible difficulties that can be involved in a practical attempt at a completely strict implementation of the encapsulation concept, which is not any kind of magical, fix-all solution for all circumstances.

The encapsulation and messaging principles appear at first sight to be a perfect way to create coding modules that are isolated from all additions or modifications to any outside code and, once they are working properly, will remain insulated from any faults that may be introduced by such code, thus making debugging much easier.

The messaging system would seem to be a very simple principle to implement, but a message, itself, has to be given the kind of data the object is able to use. If you create a new kind of message to send to a class of objects, for example, in order to request or achieve a new result, there has to be a method within the class that can respond to that message and produce that result. If there is not, you have to create one. This, however, forces you to violate the principle of encapsulation, at least in the sense that the creation of a message by one module is necessitating the creation or modification of a method in another and, indeed, this may even not fit easily with the nature of the object being thus modified.

Take, for example, the case where you want the mouse cursor to move the caret in a body of text. The text characters can be seen as instances of what might be called a 'characters' class. Their natural parameters might include their x and y coordinates within the text.

Suppose, however, you want to place the caret in accordance with whether the mouse cursor is to the

right or left of the centre of a text character. Now you will need extra, new information, being the x coordinate of the centre of a character, that is not easily seen as a natural parameter of the character within the text. Thus, you have to create a method in the class of characters that will find this coordinate, which relates completely to the requirements of the mouse cursor and caret, and has no natural role in the concept of a character within a body of text.

There is also the problem that the natural location of a character is within the body of the text, rather than relative to the program client area, or the screen as a whole, so that the natural x coordinate of a character relates to the left hand coordinate of the text as a whole. This, however, is not the natural x coordinate of the mouse cursor, which relates to the left hand edge of the program window client area. So information of the location of the text within the window client area must also be obtained, since an entire body of text can be located in different positions within the window client area.

One may say that this is no great problem, but I argue that it tends to become unclear as to which object this particular item of data should belong to.

This kind of problem can occur with objects in general, and can proliferate, and make it difficult to decide what items of data should be assigned to which object.

It is problems of this kind that have often repelled me from attempting a complete and strict implementation of OOP, in terms of messaging and encapsulation. Instead, I have used the undoubtedly valuable concepts of OOP in a less complete way, and use another method to deal with the kind of problem outlined above, which I describe in the following section:

THE CONCEPT OF AN 'IMAGE' AND AN 'ENVIRONMENT':

In the case of the above problem involving placing the caret, which indicates a tendency of the data associated with an object to become multiplied in accordance with outside requirements, I considered the possibility of avoiding this in the following way: suppose we consider all objects as being united in some common reality which might, perhaps, be some kind of common environment. I have found that this may turn out to be more satisfactory than that of objects sending messages to one another, and allows the creation of procedures, or methods, that either belong to none of them exclusively, or do not have to be exclusively associated with the data structure of only one of them.

In order to place an object within an outside environment, it is not necessary to modify the class data structure, or the array structure of the object class. Instead, the object can be copied into an environmental data structure which, for want of a better term, I call its 'image'. The environmental data structure, or image, is then an extension of the object data structure, and relates the object to all relevant environments.

There is, however, only one image for any array of objects, and is the image of the object, or instance of the class, only, that is currently being worked on. When another object of the class is to be worked on, the current image is destroyed, leaving the object with its own internal data structure, and an image of the new object to be worked on is created in its stead.

The possible environments that can be used to create the image for a text character, for example, are the body of the text, the video screen, and the bitmap used to immediately repaint the screen (if this is done by means of a bitmap). The image of the text character will contain references to all these environments, but its object data structure will not. I give below an example of the possible differences between a character object, as created via the class data structure, the array of objects it belongs to, and its image:

(Note that there are two possible ways of creating an array data structure. The first is to list all the individual object elements together, with each

complete object following the previous one (as A1, B1, C1... ;A2, B2, C2... ; etc.). The other alternative is to list the object elements in separate arrays, with each array following the previous one, which is the case as illustrated (as A1, A2... ; B1, B2... ; C1, C2... ; etc.). It is really a matter of preference as to which method might be thought to make coding easier.)

The above image data structure will be filled out as the image of the currently working instance (character) of the CHARACTER class

It is immediately clear that the image data structure is larger, or has more elements, than the data structure of the object. These extra elements involve references to all the relevant environments in which the object can be seen to be placed, and the elements themselves are constructed in a manner that names, and thus makes clear, the environments to which they refer, as in the following example:

Screen_.CHAR.XPos.s refers the CHAR object x coordinate to the environment of the program window client rectangle.

Text_.CHAR.XPos.s refers the x coordinate to the body of the text as an environment. These values will be different if the text body environment is separated from the screen environment by a margin.

The CHAR object is printed as contained within a rectangular character bitmap, and XPos.s refers to the x coordinate distance of the left hand side of this character rectangle from the left hand margin of the relevant environment. XPos.e, on the other hand, refers to the x coordinate of the right hand side of the character rectangle (s and e stand for 'start' and 'end', respectively, of the character rectangle). Since these values are separated by the character rectangle width CHAR.Width, we can write

[Screen_.CHAR.XPos.e], '=', [Screen_.CHAR.XPos.s], '+', [CHAR.Width], '-', 1

This is an example of the calculations that can be used to create the image of an object from its object data structure, which contains, and stores, only the information necessary to enable all such calculations to be carried out.

Thus, whenever a character object is to be operated on, its complete image is created first of all, and then it is the image, rather than the object itself, that is directly worked on. This principle also applies to all objects currently operating in all environments.

The creation of an image will, in fact, require the use of data from other images within the relevant environment, such as the relationship of the text to the screen in the current example. This will be a matter of specifying the text as an object within the screen as an environment. Thus we will have the image element for the x coordinate of the text as [Screen_.TEXT.XPos.s]. This value will be used in calculating elements of the character image data structure.

It is worth noting here that, in the case of the element [Text_.CHAR.XPos.s], the text plays the role of an environment for the text character whereas, in the case of the element [Screen_.TEXT.XPos.s], the text is in the role of an object within the screen as an environment. Thus, an object, via its image, can sometimes also be in the role of an environment for another object.

It is also worth mentioning that the environmental reference principle is not confined to spatial coordinates. The element in the CHAR image, Text_.CHAR.No, refers to the character number position in the text array. Screen_.CHAR.No would similarly refer to the numerical position of the current character in the array of characters currently visible on the screen, and so on.

With regard to the solution to the caret problem mentioned above, we will have to have the images of the mouse cursor and caret in the program client screen environment (these are unique objects, and don't need any separate object data structures):

Strct CURSOR.IMG, 8
el Screen_.CURSOR.Xpos, 0, 4
el Screen_.CURSOR.Ypos, 4, 4
end.strct

Strct CARET.IMG, 8
el Screen_.CARET.Xpos, 0, 4
el Screen_.CARET.Ypos, 4, 4
end.strct

In order to solve the problem of placing the caret by means of the mouse cursor, we can use the elements in all the relevant images referred to the screen environment, which is the environment in which the caret is specified. Thus we will use the x coordinates of the caret and cursor, and then the x coordinate, [Screen_.CHAR.XPos.c], of the centre of the character, referred to the screen environment, which can be calculated by adding half the character width to the value [Screen_.CHAR.XPos.s].

The method used to find the x position of the caret will involve creating an image for each character object in turn and checking the screen environment XPos.s, XPos.c and XPos.e of each character to find which pair of x coordinates contains the x coordinate of the mouse cursor within them.

We are thus working from the point of view of relating objects from the standpoint of a particular, common environment rather than from the point of view of objects, as a whole, sending messages to one another.

I would mention here, in passing, that the Screen_. environmental reference I use refers to the client area of a window as an environment. For references involving the full video screen, I always use Full.Screen_. as the environmental reference

If, now, the overall method, or procedure, used to determing a new x coordinate position of the caret is called CARET.GetCaretXPos, this will not be thought of as being a method associated with a caret object and its internal data structure, but with a caret environmental image, which can access the data of all other images currently within the relevant environment.

THE FUNDAMENTAL AIM OF STRUCTURED PROGRAMMING:

It might be argued that working with images serves to nullify the principle of encapsulation, but I don't, in fact, see encapsulation as any kind of ultimate solution, apart from the fact that it can sometimes even be a hindrance. The relevant question should not, I would say, be a matter of how to perfect a programming methodology, but rather the question as to what, after all, is the essential purpose to be achieved by structured programming.

What is most important, it seems to me, about structured programming, is that it should be such as to enable the programmer to keep track of all the values that are being altered at any one time, rather than having some kind of complete, automatic protection for the data of all objects. The concepts that were introduced by OOP, independently of encapsulation, are of the greatest value for this purpose.

I regard programming as rather a craft than a strict methodology. That is to say, I think that the task is to enable a program to be easier to understand, and thus modify or debug. If this is achieved with only a loose, or less than perfect, application of a methodology and its nomenclature, I see no point in further modifying the code in order to merely achieve the perfection of a methodology as such. If, however, a code begins to become confused and difficult to work with, then a more strict application of some structured methodology, and its nomenclature, may well become appropriate, and possibly essential. In this way I do not deny that a more strict implementation of OOP messaging and encapsulation may be more useful in some programming contexts. I thus think that a programmer should have the freedom to work with the intuition of a craftsman, but also have a methodology to rely on where necessary.

                  Part I: Part I Introduction
                  Chapter 1: Binary numbers, code, and procedures
                  Chapter 3: Assembly Language
                  Chapter 4: Assembly Language Code example
                  Chapter 5: Macros and HLA
                  Chapter 6: HLA code example
                  Chapter 7: The Windows operating system
                  Chapter 8: Data Structures
                  Chapter 9: How to Create a Windows Program
                  Chapter 10: How to Create an Exe File
                  Chapter 11: Structured Programming and OOP
                  Part II: Part II Introduction
                  Chapter 12: Debugging a Windows Program Code
                  Chapter 13: Painting the Window Client Area
                  Chapter 14: Creating Window Menus
                  Chapter 15: How to Create Toolbars
                  Chapter 16: How to Create Popup Menus
                  Chapter 17: About the Windows Clipboard
                  Chapter 18: How to Create Bitmaps
                  Chapter 19: Icons and the Ico Format
                  Chapter 20: Common Dialog Boxes
                  Chapter 21: Working with Files
                  Chapter 22: Scrollbars and Scrolling
                  Chapter 23: How to Send Data to the Printer
                  Chapter 24: Miscellaneous Topics

© Alen, June 2014
alen@alenspage.net


Material on this page may be reproduced
for personal use only.