Beginners’ Corner — Part 4
Event-Driven Programming
object-oriented Programming for xBase Procedural Programmers
by Seth Johnson
FOR PROCEDURAL programmers, adjusting to the principles and assumptions governing object-oriented programming (OOP) can be very difficult. Many dBASE mavens, having gained proficiency in the original xBase dialect, find themselves encountering this difficulty. This article is designed to help legacy dBASE programmers to cross that barrier.

The basic reason for this difficulty is that procedural programmers are accustomed to an entirely different perspective on programming from that which the industry encourages in the way it speaks of OOP. The procedural programmer often has a much more “personally empowered” outlook toward the computer itself than OOP programmers often do. They see the computer as a logic tool that they can make do anything, if they’re only willing to write the code for it. OOP programmers, on the other hand, don’t focus on coding the machine; they code the operating system. So when the principles of OOP are discussed, the procedural programmer often is left feeling short-changed.

For the procedural programmer to come to terms with OOP, the difference that counts is the difference between procedural and event-driven programming. This article explains that difference not in terms of making a case for OOP, but in terms of what’s going on “in the machine.” This is all the procedural programmer really needs to know to begin to make sense of OOP.

A few comments about Windows and how C code for Windows is written will help explain how event-driven programming works.

Windows has a “kernel” that receives messages from all of the objects that are currently active. This kernel continually sends these messages to all of the other objects.

Everything in Windows is a standard Windows object, designed so it can work within the Windows environment, sending messages to the kernel whenever something happens.

Every C program for Windows starts with a header line that receives messages from the kernel. This header is followed by a case structure, which simply says what to do for any messages that are relevant for that particular C program. So if a message comes in saying that a button was pushed, the case structure handles that event.

Every object (or form) in Windows has this header. dBASE forms have it as well. You just don’t see it, because the programming environment creates it for you behind the scenes whenever you say NEW Form().

Now, the upshot of this is that all objects communicate by way of the kernel. Even objects that you place on a dBASE form work by sending a message to the kernel when an event occurs. The kernel then sends the message back to the form’s hidden case structure, and only then does the form handle the event by invoking appropriate snippets of code — your onClick() routines, for instance.

That’s what “event-driven” processing is, at core. This arrangement explains in basic technical terms what makes OOP programming different from procedural.

A procedural program stipulates what the machine does at each increment of time. It branches based on logic put there by the programmer. When you create a menu in dBASE-IV, you write all the steps that lead up to that menu, and you process the menu choices only at that particular point where you, the programmer, lead the procedural flow.

An event-driven program, however, also “branches” in another, thoroughly pervasive way: whenever the user does something with an object designed to communicate messages to the Windows kernel. This is not really a branch in ordinary programming terms — it’s just something that occurs because one object was designed to dispatch messages to Windows, and another (or the same one) was designed to receive and handle those messages.

Now, why this approach, where everything goes through a core kernel?

There are numerous advantages, all of which also serve Bill Gates very well. Writing programs on the basis of standard objects that communicate by means of standard messages that Windows understands, lets Windows manage memory for you. It also lets Windows handle multitasking. It also lets Windows provide for the graphical interface standards, so you don’t have to write graphics code. In addition, once this standard kind of object is set up, you don’t have to worry about compatibility with different machine configurations, so long as Bill Gates provides all the device drivers imaginable (which he has, virtually).

Then there are the rationales on the side of “what’s so great about visual programming.” Standard objects like this make it possible to think of developing software entirely visually, using existing objects, and to think of the process of developing additional functionality as a matter of subclassing existing objects instead of working directly on the code that underlies the objects. This approach to programming translates into the OOP principles of encapsulation, inheritance and polymorphism.

Combine this “visual” outlook on programming with the technical memory management/multitasking/graphics interface/device compatibility advantages of the core kernel model, and you can construct a case that says visual development and OOP, made possible by means of the kernel-based operating system, enable things to “work the way users work” — that is, not according to a set of pre-reasoned logical choices that open up functions step by step, but according to the users’ wishes, allowing them to access and work with objects in whatever sequence they choose. This is the “user-driven interface” rationale, which is just a consumer-oriented take on “event-driven programming.”

Now, given that Windows provides this core kernel with so much built in (fundamentally, all those device drivers — but all the other DLLs and other functionality built in, as well), you can understand Windows’ dominance in three ways. First, pragmatics: you can’t beat Windows with a truly independent product because it would have to have all those drivers. Second, springing from that pragmatic perspective, you have an industry full of programmers writing object-oriented code much faster than any other approach could provide, so it’s increasingly hard to rationalize procedural programming, which is at heart an approach designed to tell the machine what to do, rather than the operating system. Third, you have the advantages to the consumer (standardization in numerous ways) pushing for this kind of programming.

Event-driven programming feels different from programming in legacy dBASE code. The legacy dBASE product provided a metaphor for the machine, whereas the Windows versions of dBASE provide a metaphor for the operating system, giving you the Windows visual and event-driven interface. The legacy xBase commands implicitly said things about the machine, not about how to create the kind of independent objects that are necessary to fit the event-driven model. This is why SET RELATION feels different to the legacy dBASE programmer from how OOP feels. This command sets up a machine state, telling the environment to manage the details that support a relationship between tables in the machine’s memory space. Windows, however, is designed for you to let the operating system manage memory.

The way dBASE does both xBase and OOP at the same time is by creating a “virtual machine” which can understand xBase commands and set up a work environment the same way the legacy dBASE compiler/interpreter handled the machine’s memory for the procedural programmer. But the virtual machine also creates standard Windows objects, which work much better in the Windows environment.

If you’re writing event-driven code, you’re not taking charge of the machine, setting up every option in logical sequence. You’re writing event handlers, because you’re writing a program that can be managed by the Windows kernel. When you combine this approach with a belief that the right way to program is visually (because you can’t get something good enough to market soon enough, otherwise), you often get the idea that’s common among OOP programmers: that procedures are really supposed to only be these little event handler snippets.

However, the beauty of the dBASE virtual machine/ interpreter/ compiler and the dBASE interactive development environment is that you also can see the source code, and you can do more with your programs as a result. When programmers take on a strictly visual encapsulation metaphor mindset, they often tend to, in effect, give up on computer science and think less about their own new generic algorithms and ways of programming the machine, and much more about what’s efficient in terms of how to code quickly in the operating system environment.

This is why dBASE’s two-way tools are particularly special for independent developers.

But in any case, you still have to understand that you’re not going to be writing something that works efficiently in the Windows environment until you see that you’re going to be coding objects that float around in Windows, sending and receiving messages to and from the kernel, rather than trying to take the user and the machine in the directions you want to take them.

All procedural programmers really want is to know what the machine is doing. Once they understand the mechanics of event-driven programming, they can find their own way to come to terms with object-oriented programming. A clear-eyed analysis of the mechanics of OOP is the best way to enable the dBASE legions to come into their own once again. Hopefully this analysis will help bring that about.

The author would like to thank Dwight Purdy and David L. Stone, his proof-readers, for the improvements they brought to this text.