The scene: At an animal research laboratory, a beaming researcher directs reporters' attention to a window in a room-sized box on the floor before them. Inside the box, a bored-looking gorilla sits on the floor and picks fleas from his tummy.
"We've created this experiment to measure the cleverness of gorillas," says the researcher. "We've carefully designed this cage so that there are only three ways to get out. We're monitoring the cage continuously to see how quickly Grunion hits upon a way to get out, and which one he chooses."
Inside the cage, Grunion just sits there, scratching.
"He seems to be in no hurry to get started," observes one of the reporters.
"Gorillas can be stubborn," rejoins the researcher. "He'll get down to business shortly."
But as minutes pass, Grunion shows absolutely no interest in finding his way out of the box. The reporters begin to yawn. The researcher grows restive.
"Hmmm. He may not be feeling well today. I'd better go in and take a look at him." The researcher unlocks the door in the side of the box and goes in.
Grunion immediately perks up, grabs the researcher, and throws him at the wall so hard that the entire side of the box collapses outward. Grunion then lopes out of the box and gives the reporters the High Five.
Moral: There is always another way out of the box. Plus: Even if you built the box, you may not know the best way out. And finally: Never be too sure you're smarter than the gorilla.
Way back in 1985, when I was a foot soldier at PC Tech Journal, each of us on the editorial staff was given an early copy of Microsoft Windows. I loved it. It was wonderful, the realization of Xerox's inaccessible PARC research for the common man. Naturally, I immediately wanted to write applications that used it. So I called Microsoft and asked for whatever it took to generate a Windows app, affectionately known as a "winapp."
A couple of days later, the Federal Express man rolled this thing in on a forklift and I was on my own.
Sheesh!
The Microsoft Windows Software Developers' Toolkit (SDK) is a massive collection of facts and diverse utilities poured into a box with little thought to organization or documentation clarity. It is the second most daunting developers' tool I have ever confronted; the first (as I'll return to a little later) is the SDK for OS/2 Presentation Manager.
The Windows SDK makes it pretty plain that you can write a winapp in one of two languages: Microsoft C or MASM. Being neither a masochist nor suicidal, I called Microsoft and complained. There were but two (brutally difficult) ways out of the box, and I cared for neither. How about some bindings for Pascal or Modula-2? And cripes, how about coming up with some reasonable documentation?
Their answer was and is most informative: The Windows SDK is intended for use by experienced professional developers. In other words, if you have the head muscle to design a major application that can compete on the open market, you've got the head muscle it takes to untangle the unholy mess waiting inside the SDK box. Programmers in kiddie languages need not apply. Ah, well. It was a fond dream ... and like Grunion, I sat back in my cage and waited for someone to provide another way out of the box.
I was a while waiting. In the meantime, Microsoft was moaning about how nobody was jumping on the Windows' bandwagon. Nobody was using it -- perhaps not remarkably because there were no applications of consequence for it. This may have seemed incomprehensible to Microsoft, but it was pretty plain to me: Most professional developers were looking at the cost/ benefit equations presented by the Windows SDK and deciding that the costs outweighed the benefits by about fifty to one.
So I waited. While I was waiting, I thought a lot about how Windows development could be done more easily. Consider the nature of the box: There are about 520 different API calls for Microsoft Windows 2.0. This is cool; Windows is a capable and complex gadget that does a lot of interesting and difficult things. Furthermore, Windows is an event-driven system. At unpredictable times, the Windows machinery alerts your winapp that significant things have occurred: Mouse clicks, window overlaps, things like that. The windows comprising your application must then react to those events somehow.
The main problem with the Windows SDK is that it makes little or no effort to organize its API calls and other information in hierarchical fashion. It hides nothing, in keeping with the C philosophy of giving the programmer control over everything. However, the C folks never seem to catch on to the fact that invisible does not mean inaccessible. The essence of structured programming, according to old Nick Wirth, is the artful hiding of details: Hide the stuff you don't need so that it doesn't overwhelm your perception and understanding of the stuff you do need!
Most of the stuff in the SDK can be kept hidden and out of the way about 90 percent of the time. (Instead, it hangs in your face like cobwebs and makes the whole process look murky and incomprehensible.) My suggestion has always been that a carefully-crafted bindings library could provide a header file full of useful defaults that don't need to be tweaked until necessity arises. Very high-level procedures in the library would allow creation of windows and dialog boxes with one call rather than twenty. A winapp should need to be no larger than this:
As part of the functioning of InitWinApp, the init code would fill all the necessary descriptor records with usable default values. The programmer could override those default values any time that the default values just wouldn't serve. Alas, there is no Pascal library like this, so don't call me up at three ayem asking me where to buy it.
Microsoft wasn't listening back then, and as best I know they're not listening today. While waiting for someone to implement my obvious way out of the box, a small company near Chicago came from nowhere and provided yet another way out, a way that was years ahead of its time and flew right past nearly everybody in the industry in 1986: objects. The company is The Whitewater Group, and the product is Actor. If you have a hankering to do Windows, let me be pretty blunt about it: Actor is the only way to develop applications for Microsoft Windows that is worth the trouble it takes. Period.
Actor is a wholly synthetic language developed by Whitewater cofounder Charles Duff, who earlier implemented the idiosyncratic Macintosh language called Neon. Actor is not an extension of any earlier language, though it contains elements of many. If you're familiar with either C or Pascal it won't seem totally alien, and if you've learned Smalltalk as well, it'll seem downright traditional by comparison.
Actor manages the complexity of the Windows API by modeling the elements of the Windows GUI (graphics user interface) in object form. The Window class models windows. The ScrollBar class models the scroll bar control that may optionally be added to a window. Creating an instance of a Window class hides the complexity of window creation behind a single easy-to-grasp metaphor: The Window class acts as a "window factory" and whacks out a window object for you to use. Very visual, very intuitive. All the ugly little details of setting up a window are hidden behind that object metaphor.
Actually, the Window class is never really instantiated, because a vanilla-flavored window isn't good for much. Window is a formal class in Actor, which is the equivalent of the abstract class or abstract object type in Quick and Turbo Pascal. Child classes of the Window class add additional code to specialize the generic window: TextWindow can display (though not edit) ordinary text. EditWindow is a child class of TextWindow that can edit as well as display text, and so on.
Every important service Windows offers is modeled somewhere in the Actor class hierarchy. The hierarchy manages the Windows API complexity in two dimensions: First, Actor distributes the specification of Windows functionality up and down the class hierarchy by degree of specificity. The most general concepts (windows, controls, and so on) float to the top and the most specific concepts (file window, button, polygon, and so on) move to the bottom. Second, Actor hides the implementation of Windows functionality (that is, the gritty details of calling the API and handling events) behind the graspable masks of the individual classes.
This dual-mode management of complexity (idea complexity and implementation complexity, both at once) is perhaps the greatest gift object-oriented techniques offer the programmer. Actor uses it to the fullest, both to manage the complexity of the Windows API and also Actor's own very rich class library.
The notion of a rich class library is extremely important, and I haven't really taken it up so far in my discussion of OOP concepts. If you've seen Whitewater's excellent ad describing how to write a text editor in two code statements, you'll begin to get a feeling for the complexity-hiding leverage Actor affords. It really is that easy to create a text editor in Actor:
In the first statement the object MyEditor is instantiated from the EditWindow class, by sending the New message to the class. In the second statement, the new window object MyEditor is made visible by sending it the Show message. (I'll get back to this notion of message passing again shortly.)
This is not just a matter of making Windows API calls. Actor actually comes with a fully functional text editor object in its class library. This is the rough equivalent of something such as the Turbo Pascal Editor Toolbox with all the loose ends tied up and tucked in. Nothing ties up loose ends such as encapsulation. The cleanness of interfacing to an object that may represent tens of thousands of lines of code is one reason Actor can offer things like a text editor class, and is a major reason earlier languages had a tough time with toolbox products.
Actor offers lots of additional library classes, some with considerable power and many with no analog in the purely structured world. Under the formal class Collections (which is Actor's name for what we would simply call data structures) are a number of interesting critters. One is Bag, which metaphorically is just what its name implies: A container in which you can toss any objects you like. The class keeps track of what's in the bag, and how many are there.
Bag bears some relation to Pascal's set type. Sets in Pascal only deal in values, not variables, however; and a value is either in a set or not in the set -- Bag can tell you how many objects of a given class are present.
The TextCollection class resembles the melding of a Pascal text file held completely in memory with a simple line-oriented editor such as EDLIN. TextCollection data is some number of string values, and the class has a suite of methods for inserting, deleting, and replacing lines. Actor uses TextCollection as the mechanism for communicating with the Windows clipboard resource. Text from a TextCollection may be written to or read from the clipboard through methods defined for the purpose. You might think of TextCollection objects as sheets torn off the Windows clipboard -- a handy metaphor for what is a very handy thing to have in a library.
Another important collection class is the Stream class, which resembles an array of objects, where the objects can be of any class at all. Streams can be handy for things like lexical analysis when held entirely in memory, but are probably most useful for writing objects to disk files. Turbo Pascal 5.5 has a similar Stream type, as does C++.
It's possible (if not easy) to provide libraries of routines defining text editors, windows, and buttons for ordinary structured languages. It takes the power of late binding and polymorphism, however, to implement things such as bags and streams in which the elements of the data structure can be any type at all.
This is one of the numerous reasons that rich runtime libraries really come into their own in an object setting. Not only does encapsulation make libraries clean and easy to understand and use, but polymorphism allows a richness of data expression that older purely structured languages simply cannot match. Just try to code up a bag in preobject C or Pascal. Generic pointers might give you a fighting chance, but the resulting Hackenstein's monster would be an ugly thing indeed.
By now, a good many people have sampled OOP concepts in the forms of Quick Pascal and Turbo Pascal. People evaluating Actor will more and more be doing so not from a platform of total ignorance but simply from different OOP implementations. Actor has all the object-oriented features that C++ and Object Pascal have, but as with Smalltalk (as I described a few columns ago) the jargon can be confusingly different.
Polymorphism is a case in point.
In C++ and Turbo Pascal 5.5, polymorphism is an option rather than a way of life. Your methods can be virtual (meaning that they support polymorphism) if you choose, but they default to being early-bound (static), just as ordinary procedure calls are. (Quick Pascal, on the other hand, makes all methods virtual, period.)
In Actor and Smalltalk, everything is an object and all method calls are late bound. Both languages use the same jargon in describing polymorphic method calls: Instead of calling a method directly (which would imply early binding) you call an object's method by sending that object a message indicating which method you wish to call. The object then uses the message to select which method code is actually invoked.
If you learned polymorphism in a Pascal or C++ context, this probably sounds pretty weird. The mechanism is called message passing, and it deserves a little elaboration.
Think of it this (rather literal) way: Imagine that you, as a farmer, find a note in your mailbox one morning from the county agent. The note simply says:
Up and down the county roads, other farmers find the same message in the mailbox. What does each one do?
It depends on the nature of the crops each farmer grows.
If you're a cucumber farmer, you crank up your cucumber-picking machine and head off down the rows in your fields. If you own a cherry orchard, you haul out the tall ladders, call out the kids and your hired hands, and start in on the trees. The act of picking cucumbers is nothing like the act of picking cherries, but both actions amount to a reasonable response to the directive HARVEST YOUR CROPS.
The "many shapes" of crop harvesting are a form of polymorphism. The county agent simply tells the farmers in his district what to do -- not how to do it. The farmers each know how to harvest their own crops. And they do it, each in an appropriate way.
Back in Actor, consider a collection (a bag, say) of various objects. (Keep in mind that everything in Actor is an object, right down to characters, strings, and numeric digits.) You want to print out the value of every object in the bag. The way to do this is to send the Print message to every object in the bag. Each object then reacts to the Print message by selecting the correct Print method to invoke. A string object will print using one method, but a numeric value object will need to use a different method -- one that first converts the numeric value to a string and then displays the string to the screen.
If you think about it, this is really no different than the situation in Object Pascal. Remember, that when virtual methods are inherited down an object hierarchy, the name of the virtual method is always the same, even when the implementation of the method is different. In a sense, when you make a virtual method call you pass the name of the method to the object in question, which then looks the name up in a table to determine which implementation of that named method to invoke. The name of the virtual method is thus a message: PRINT YOURSELF. The receiver of the message must decide what code will in fact do the job and satisfy the directive.
So beneath it all, message-passing and virtual method calls are functionally the same thing. Don't let the jargon get you down!
Although, Actor uses some of the same jargon as Smalltalk, it's an easier language to learn because the bones of language are implemented in more familiar form. Passing a message to an object looks a heckuva lot like a Pascal procedure call:
Here, we create an instance of the OrderedCollection class (think of it as an array with a built-in stack pointer) and call it MyStack. Notice that the assignment operator and syntax is identical to Pascal's. Two Add messages amount to pushing two values onto MyStack. You could implement a stack type in Pascal and create an Add procedure that would have the same sort of interface.
In a fashion similar (if not identical) to C, an Actor method is defined by creating a header and then enclosing some number of statements between curly brackets:
Actor's control structures, while using slightly different syntax, incorporate most of the familiar Pascal keywords and are easy to recognize and understand. Conditional statements are pretty plain:
The looping construct can be set up in a number of different ways, but it reads well in any configuration. This one is set up as a while/do loop:
Actor's designers have taken considerable pains to keep "weirdness" out of the language; the only weirdness is the inescapable weirdness of object-oriented thinking, which like kudzu is destined over time to replace whatever else is out there.
Given the enormity of the things it does (such as taming the Windows API) I found Actor almost ridiculously easy to learn. The trick, again, is not in the language but in the paradigm. Once you learn to think object-ively, you shouldn't have any more trouble than I had.
The documentation is solid, if not exhaustive. The single fat (700 page) volume hasn't failed to provide me what I've needed to know so far, which is my early measure of language documentation. I haven't yet tried to do anything really tricky, such as using the early-binding option or create a stand-alone application, but I hope to report on both in future columns, and we'll see how well the doc stands up in a pinch.
On the low end, the manual is a so-so introduction to OOP thinking. I'll forgive them that, and in fact I prefer that they'd give the language its due in the manual and let us joinalists anoint the great unwashed in object-oriented First Principles. If you've already made the conceptual breakthrough to objects, on the other hand, you'll have no problem at all picking up Actor itself.
There is also the book by Marty Franz, Object-Oriented Programming with Actor, that takes a slower, more gentle path to OOP. Marty has a clean, plain style and goes into the mindset of Actor programming in a way that the manual itself doesn't have room for. If you're going to go the $500 to acquire Actor, it's well worth shelling out another $25 for the book.
Which brings us to the question of Actor's success in the marketplace. Pretty obviously, Actor has hitched its wagon to Windows, and won't do any better than Windows does. Windows, however, is alluvasudden on a roll, fueled largely by the availability of $2000-386 machines that make Windows not only fast enough but almost sprightly. The Windows installed base has probably achieved a sort of critical mass, with even Borland announcing that they will pursue Windows development in their languages.
The way I see it, Actor has only one serious impediment to its success: Its $500 price tag. Compared to the Windows SDK it's cheap enough, but an impulse buy it is not. If a Tiny Actor (Child Actor?) were available for the canonical $99, there'd be no stopping it. Microsoft has done well with its Big C/Little C approach. Whitewater should pay heed. Actor is the way to break out of the Windows software development box, but for Grunion the Gorilla to knock out a wall with it, Actor first has to get in the door somehow.
And then there is Presentation Manager. PM is to OS/2 as Windows is to DOS: The anointed user interface and graphics toolkit. Like Windows, it has an SDK, which is larger, richer, and perhaps even a little better organized. Unfortunately, because PM does lots more than Windows, the end result is the same: You could spend years getting good enough at the SDK to write a competitive product with it. (Not to mention the endless irritation of having to write in C.)
Ever since PM was announced, I've been thinking, "Somebody should do an Actor for it." The whole nature of PM, like that of Windows, cries out for an object-oriented development language. Both of the current books I've obtained on Presentation Manager programming describe PM internals in object-oriented terms, even though the example code is in plain old-fashioned C. If you intend to work in PM I'd suggest you get them both: Alan Southerton's Programmer's Guide to Presentation Manager is nicely done, if a little thin on figures and example code for my tastes. Even so, it runs to 750 pages -- there is a lot to cover.
The book to have, though, is the one bundled in the Microsoft PM SDK: Programming the OS/2 Presentation Manager by Charles Petzold. (Details on both books are given at the end of the column -- but remember not to buy Petzold's book if you're also going to buy the SDK!) Lord knows what Microsoft would have done without a writer like Charles Petzold to make sense of it all. In 850 pages he makes PM development about as rational as it's ever going to be. Lots of code, lots of figures, and beautifully written. To get a handle on PM internals, start here.
I've encouraged Whitewater to do an Actor for it, and they well might -- or let us hope. In the meantime, however, Digitalk has gone and done the remarkable, which is to produce a Smalltalk for PM -- one that adheres totally to the PM user interface spec.
This is remarkable because Smalltalk, the language, was defined with its own user interface, and up until now Digitalk has been relatively faithful to that interface, perhaps for fear of being accused of "tinkering with the standard." Their latest move is the right one. Smalltalk has its own user interface spec because when it was designed (mid-seventies) Batch was King, and user interfaces didn't exist. For the same reason that UCSD Pascal was designed with its own operating system, Smalltalk-80 had its own user interface. But operating systems have become standardized with user interfaces right behind.
I've had very little time to experiment with Smalltalk/V PM, mostly because getting OS/2 to run on a Frankenclone is ticklish business. (The product itself, even in its unfinished state, is pretty robust.) At this writing the product is still in beta test form. I'll have a lot more to say about it when I receive the shrinkwrapped product.
For now, here are some of the important points:
And welcome to the real world, Smalltalk.
Copyright © 1989, Dr. Dobb's JournalForklift Toolkit
The Nature of the Box
PROGRAM Yo;
USES WinLib;
BEGIN
InitWinApp;
OpenWindow(WindowHandle, 10,10,40,5,'Window Title');
WriteToWindow(WindowHandle, 'Yo, World!');
WaitUntilWindowClose(Window-Handle);
END.
The Way Out
The Importance of a Class Library
MyEditor:= New(EditWindow, ThePort,"editmenu", "Editor",nil);
Show(MyEditor,1);
Polymorphism via Messages
KILLER FROST TONIGHT. HARVEST YOUR CROPS NOW!
Familiar Bones
MyStack:= New(OrderedCollection,64);
Add(MyStack,17);
Add(MyStack,42);
Def MyMethod(self,Foo,Bar)
{
DoSomething;
DoSomethingElse;
AndSoOn;
}
if (i < 10)
then DoSomething;
else DoSomethingElse;
endif;
loop
while x < 42
x:= x + 1;
print(x);
endloop;Actor on the Scales
OS/2, Mon Dieu!
Presenting Smalltalk
Yes, it's a dialect, but so was Turbo Pascal -- which has weathered the rain of brickbats from sourpuss academicians. Digitalk has done the right thing, both from a Smalltalk perspective and a Presentation Manager perspective. C is not an appropriate language for use in developing for a GUI. (C++ is, of course, but that's another person's column.) Smalltalk, as it was, seemed chained to the late seventies, trapped in a set of assumptions that simply don't apply to our modern machines and operating environments. In a future column I'll use Smalltalk/V PM to show you just how utterly simple it can be to develop for Presentation Manager. Thanks, Digitalk, for a bold step.PRODUCTS MENTIONED
Actor V 1.2
The Whitewater Group
906 University Place
Evanston, IL 60201
312-491-2370
$495.00
Object-Oriented Programming with Actor
by Marty Franz
Scott, Foresman & Company, 1989
ISBN 0-673-38641-4
$24.95
Programmer's Guide to Presentation Manager
by Alan Southerton
Addison-Wesley, 1989
ISBN 0-201-19440-6
$26.95
Programming the OS/2 Presentation Manager
by Charles Petzold
Microsoft Press, 1989
ISBN 1-55615-170-5
$29.95
(Bundled with Microsoft's OS/2 PM Software Developer's Toolkit)
Smalltalk/V PM
Digitalk Inc.
9841 Airport Blvd.
Los Angeles, CA 90045
213-645-1082
$499.95