Ad hoc Programming
What is Ad Hoc Programming?
Ad hoc programming is a style of object oriented programming that focuses on objects created for specific purposes. Rather than implementing an elaborate class hierarchy, and partitioning of data into objects, ad hoc programs focus on representing the semantics of the program in terms of the relationships between objects, and the permutations there of. As such, objects become much more fluid things, often taking on and discarding properties and methods through the course of a program. Inheritance is not a product of derivation from a base class, or even through a prototype chain, but rather through a shallow copying of another object's properties. Any object may serve as the basis of another, and properties can be mixed together and shared, just like genes are through sex.
Ad hoc programming is not only a stylistic exercise. Rather, it represents a significant change in the conceptual basis for programs. The notion of class, for example, ceases to define an implementation characteristic, and instead is repurposed with a new definition. In ad hoc programming, a class is the set of messages to which member objects must respond. An object is said to be a member of a class if and only if it responds to each method of that class. And since an object may gain or lose methods at any time, so to may the object change its classes at any time. More over, as an object may implement the methods of any number of classes, an object may belong to an number of classes at one time. In this fashion, classes serve to classify objects, and are used as a runtime check to ensure the existence of the necessary semantic elements.
Another difference between ad hoc programming, and traditional object oriented programming lies in its usage of data. Ad hoc objects do not necessarily define an associated data structure, rather the object itself consists of a set of named slots (similar to the Self Programming Language, that operate upon other data structures. Consequently, objects are generally not used to represent all of the data manipulated by the program, but rather only that data that represents the program itself. For example, in an ad hoc program, there may be only one JPEG object, which knows how to decode and encode JPEG data. The JPEG object does not contain the data of any given file, but rather knows how to transform that file into another useful format. Similarly, there is probably only one Keyboard and one Mouse object, for any given program. If you happened to have a second mouse, you may create a clone of the original mouse object and have it read the second mouse device, but there is generally not need for more than one of any object type. As such, ad hoc programs do not in general generate garbage. But rather, continually reuse what resources they initially reserve.
What does Ad Hoc Programming Look Like?
(An object named: Jane) has: #greets: of: Transcript show: 'Hi ' , your name , '! My name is ' , self name; cr .
(An object named: Bob) from: Jane.
Jane greets: Bob.
Bob greets: Jane.
Jane has: #wavesTo: of: Transcript show: 'Goodbye ', your name , '!' .
Jane wavesTo: Bob.
If you ran this in a Squeak image with the Adhoc package loaded you'd have a Transcript window with the following contents:
Hi Bob! My name is Jane
Hi Jane! My name is Bob
And while this might not seem like much, this represents a significant departure from what one would typically do to implement these same features. If we examine what this code does, you can see where the ad hoc approach can transform your coding. This example actually requires use of a specialized parser to run, and uses a different base object from normal Smalltalk code.
Adhoc explicit symbols.
You can reactive this feature using the corresponding:
Adhoc implicit symbols.
This style of chained sends, modifying the state machine of an object is also a design principle upon which most ad hoc programs are built. Rather than writing a single line with a single semantic action, actions are combined into complete thoughts much like sentences in English. Structuring the semantics of a method invocation is actually more important than getting the implementation details right. In the previous example, the #has:of: method set the property #greets: on the object Jane. The value of the property was set to a block closure which displayed a message in the transcript when invoked. This block closure is executed by sending the #greets; message to Jane a couple lines down.
Probably most importantly, however, is the line which states:
(An object named: Bob) from: Jane.
What this line does is create a new object named Bob, that derives its properties from Jane. We could derive Bob's properties from multiple objects, by chaining multiple #from: message sends, which would result in additional properties being added to the object. When the message #greets: was sent to Bob in our example, some under the hood magic, altered the block closure's bindings to point to Bob instead of Jane, which allowed Bob to respond to Jane in the correct fashion with no additional code being written. Similarly, we then added a new method to Jane after the fact, so that she could say goodbye.
Had we tried to invoke:
Bob wavesTo: Jane.
Nothing would have been added to the Transcript, and a nil value would be returned. This is because, Bob was derived from Jane prior to her learning how to #waveTo: someone. By default in an ad hoc program, any object which receives a message that they can not handle will simply ignore it and return a nil value. As such, any object can pass any other object any given message without fear of an unrecoverable error. This feature combined with the sort of sexual reproduction of objects, makes ad hoc programming eminently suitable for evolutionary programming.