al@aurora.UUCP (Al Globus) (10/04/85)
My earlier posting regarding Objective C elicited a number of responses, many of whom wished to know more. The following is much of my knowledge and experience with object programming and Objective C. For the purpose of this piece, object programming refers to a programming methodology limited to a single process, on a single processor, within a single address space. No parallelism is implied by the term message (see below). There are other meanings for object programming, but they are not addressed here. Objective C was developed and is marketed by PPI, 27 Glen Road, Sandy Hook, CT 06482 (203) 426-1875. The primary advantages of object programming and Objective C are improved modularity, reduced code bulk (lines of code), and a better mapping between many problems and the software. I was originally attracted to object programming because it could have solved some of the problems I ran into developing a dynamic display editor (completed in C a year and a half ago). Specifically, I think that using Objective C I could have built the editor in 4-5,000 lines of code rather than the 20,000 or so it actually took. The result would have had better modularity and taken perhaps 35% less time to complete. Powerful incentives. I have used Objective C to implement a prototype of a simulation. This simulates the activities of the crew on-board NASA's space station which is to be launched in the early 1990's. The prototype went well and we are now a few weeks away from finishing the first beta test version. This work has also gone well, somewhat better than expected actually. All told I have written about 1500 lines of Objective C. Objective C is a preprocessor for the C language. It adds SMALLTALK-like messaging, objects, classes, and inheritance to C. The preprocessor runs after the C preprocessor and outputs C source code. Normal C code is passed through unchanged, so you keep all of C. Essentially, Objective C adds syntax to declare classes and messages; and a new expression, messaging. The messaging expression has all of the properties of any C expression, i.e., it evaluates to a value and can be used anywhere a normal C expression can be used. Object programing software consist of objects that exchange messages. Think of objects as synthetic machines or people that remember information, do particular things, and interact by sending each other messages. Since the real world consists of objects that interact, object programs frequently reflect the problem domain better than convential techniques (i.e., operators that work on operands). Objects contain both code and data. The data is private and can (normally) only be accessed directly by the object's code (as usual in C, there are ways to get around this). Every object is a member of a class. Each class consists of one FACTORY object and zero or more INSTANCE objects. The factory object is usually used only to create instance objects. Every instance object in a single class has the same data structure, although values may vary, and the same code. This code is called the object's METHODs. Each method corresponds to a message that the object understands. Programming in Objective C is mostly a matter of writing classes. Each class goes in a separate file. In summary, objects are chunks of code and data with a single pointer to the whole mess, rather than a pointer to the data and a pointer to each function that works on the data as in conventional data hiding approaches in C. This improves modularity at a very fundimental level. Messages are somewhat equivalent to function calls. Messages cause a piece of code to be executed, can have arguments, and return a value. The difference is that the code executed and the data worked on depends on the object the messages is sent to. Messages give several advantages. One is that you can add new sorts of things (classes of objects) to a system without modifing the code that tweeks these objects, causing them to save to disk for instance. Another is that the name space of messages is partitioned between classes so name collisions are infrequent; thus the practice of prepending names with characters to identify different parts of a large system becomes unnecessary and names like IPDJMOVE disappear. Also, when you change graphic libraries you don't get the name collisions that have cost me several days of frustrating debuging. Finally, the giant switch statements common to programs that must deal with many different kinds of data disappear. These switch statements usually switch on a field that tells the type of the data and the code (semantics) for each type goes into the case portion. With Objective C the semantics go into each separate class. This gives better modularity and reduces code bulk a bit. The last major property of object programming is inheritance. Classes are arranged into a heirarchy (a tree) with the Object class at the top (root). Each sub-class inherits all of the data structures (INSTANCE VARIABLES) and methods of its superclass. In general, sub-classes are specializations of their super-class, with the Object class being the most general of all. Inheritance saves large amounts of code since sub-classes need only add the new methods and data they need and over-ride any methods that are inappropriate. In addition, new data and/or methods can be given to all objects in a system simply by modifying the Object class. Inheritance, then, can reduce code bulk substantially. Reduction in code bulk can save enormous amounts of money in large systems. According to Putnam, a software metrician, life cycle software cost is proportional to the cube of code bulk. Since theoretical consideration and some empirical evidence suggest that object programming can reduce code bulk by a factor of 2 to 10, in principle cost should be reduced by a factor of 8 to 1000. I don't know if the savings are that large, but they may be substantial. Objective C has got some additional nice stuff for the working programmer. First, there are two messages defined by the Object class, storeOn: and readFrom:. storeOn: will save any instance object and all the objects it references recursively to disk in a readable ascii file. readFrom: will read a file created by storeOn: and recreate the same graph of objects. I.e., with one line of code you can save or retrieve ANY data structure created out of objects - or send it around the world on the net! Second, all messages go through the messaging function. There is a global flag, msgFlag, that, when set, will print out a trace of all messages. This is incredibly useful for debugging. When you get bus error - core dumped, just run the program again with msgFlag set (I set it from the command line) and the trace will tell you right where the crash occured. Third, if an object receives a message it can't understand you get an error message and a stack trace leading you directly to the problem. Lastly, PPI provides a number of classes with the compiler. I have found these to be extremely useful. Objective C isn't perfect of course. Here are the main disadvantages I've found: Too expensive. I wish they'd cut the cost and sell thousands of copies. It may be worth the current price, but that doesn't mean enough people will buy it. Its got a few bugs. None of them have hurt too badly but the system is not as mature as it could be. PPI's support has been excellent and I think this problem will eventually be ironed out. Compile time is long. Objective C does a full parse of C and then spits out a complete C program which must be parsed by the local compiler. PPI is working on an interpreter call VICI that may solve this problem. Classes are divided into groups called phyla. I still don't understand phyla and have had problems as a result. Phlya are used to optimize message passing and are a pain in the .... Object programming is not appropriate for all problems. It has been used for compilers, operating systems, simulations, and user interfaces at least. I'm not sure exactly what the boundaries of usefulness are. Its not available on the MacIntosh. Speaking of availablility, Objective C is available on a lot of UNIX systems and the IBM PC. PPI is working on MacIntosh and VMS versions. The bottom line: I love it. I hope I never have to go back to functions and data structures, objects are for me. I also convinced NASA (I'm a contractor) to spend almost $20,000 on object programming software, and we're real short of money these days.
richw@ada-uts.UUCP (10/11/85)
GREAT! (I'll flame later about some reservations I have). First of all, I'm extremely glad that someone's pointing out the benefits of object-oriented programming and C's deficiencies (esp. naming, as in IPDJMOVE -- arggh!). Object-oriented programming pretty much requires the ability to define many different "add" procedures (as an example) -- naming them add_complex, add_matrix, etc. in "normal" C is a very limited solution. (see the end of this note for an example of a better(?) solution). Does Objective C provide what Smalltalk calls "blocks"? If so, I'm even more impressed -- blocks allow one to build sophisticated control structures, e.g. exception handling (for instance, a message like "dictionary lookup: key ifNotFound: block"). Nevertheless, I have two reservations about Objective C. The second, concerning inheritance, is intended to give another viewpoint on something that, on the surface, looks wonderful but has its disadvantages. Expressive power is an advantage of inheritance, but modularity... (1) If and when someone implements a production-quality compiler for Smalltalk (incremental compilers already exist), it seems Objective C will be, in comparison, a less coherent jumble of two languages. While some of the features of C (e.g. access to very low-level machine details) might be useful in a Smalltalk, ideally a NEW language would be the solution -- one with ONLY those features desired (and maybe borrowed from C and Smalltalk), not the mess that results from merging two languages. (2) My second reservation is actually a criticism of inheritance in general. While it is very true that data-abstraction helps improve the modularity of a program, inheritance requires that a person trying to implement a particular (sub)class need understand many, if not all, of the details in its chain of superclasses. That INCLUDES details about the "rep" (representation) of each superclass, since the rep, or "instance variables", are also inherited. "Simple" data abstraction allows rep-details to be hidden and ignored. Inheritance detracts from this! Rather than subclass to extend the functionality of an object, I think a more modular approach involves implementing the extension by USING the original object as part of the "rep". Borrowing a Smalltalk example, rather than make Dictionary a subclass of Set, have Dictionary include a Set as its one of its instance variables. Formerly inherited messages could be re-implemented with simple one-line procedures (or "methods", to use Smalltalk terminology). None of this requires an inheritance mechanism, but provides a lot of the same advantages. Now, if you want to change the Set's instance variables (rep) without changing its visible functionality, Dictionary need not be changed at all! If Dictionary were a subclass of Set, it would have to be rewritten too. Thus, subclassing makes Dictionary LESS modular. At least Objective C doesn't have multiple inheritance. :-) -- Rich Wagner P.S. I'm not alone in these reservations -- a few well-known and respected MIT C.S. professors I know feel the same way... ------------------------------------------------------------------------- /** Faking data-abstraction in C **/ static push(stack,obj) Stack *stack; Element obj; { . . } static Element pop(stack) Stack *stack; { . . } struct { void (*push)(); Element (*pop)(); } Stack_Class = { push, pop }; ----------------------------------------------------------------------- A call to one of these stack procedures would then look like e = (*Stack_Class.pop)(s); Note this looks somewhat like Ada, except for the (* ) around the selector. It, at least, doubles the number of significant characters in the name of a procedure. It also cuts down on the number of names defined per data-abstraction or class (1 versus X, where X is the number of procedures defined. However, this does slow down procedure calls because of the selection and de-referencing (ignoring possible compiler optimizations). I still prefer REAL object-oriented languages...
keith@cecil.UUCP (keith gorlen) (10/13/85)
>Does Objective C provide what Smalltalk calls "blocks"? If so, No. >(2) My second reservation is actually a criticism of inheritance >in general. While it is very true that data-abstraction helps >improve the modularity of a program, inheritance requires that >a person trying to implement a particular (sub)class need understand >many, if not all, of the details in its chain of superclasses. >That INCLUDES details about the "rep" (representation) of each >superclass, since the rep, or "instance variables", are also >inherited. "Simple" data abstraction allows rep-details to be >hidden and ignored. Inheritance detracts from this! This is not necessarily so. In some object-oriented languages (e.g. C++) the private instance variables inherited by a subclass are not (normally) accessable from the subclass, except via the superclass's public methods. Thus, the details of the implementation of a superclass chain are just as hidden to the subclass as they are to any user of the superclass. >Rather than subclass to extend the functionality of an object, >I think a more modular approach involves implementing the >extension by USING the original object as part of the "rep". > >Borrowing a Smalltalk example, rather than make Dictionary a >subclass of Set, have Dictionary include a Set as its one >of its instance variables. ... This is indeed a good example of where the decision to implement a class by subclassing a similar existing class or by using the existing class as an instance variable is not clear-cut. There are situations, however, in which inheritance is the mechanism of choice. Consider an abstract class such as Smalltalk's "Link" class, which is used as the superclass of objects to be placed on "LinkedList"s. It encapsulates the linkage pointer of its subclasses and permits class LinkedList to be implemented in a general way so that it can manage a list of any objects that are subclasses of Link. Class Link serves to allocate the linkage pointer at a consistent offset in its subclasses and allows class LinkedList to verify the type of objects being added to the list via the "isKindOf" method. Simple use of an existing class as an instance variable of another object does not confer these properties. >A call to one of these stack procedures would then look like > >e = (*Stack_Class.pop)(s); >... >is the number of procedures defined. However, this does slow down >procedure calls because of the selection and de-referencing >(ignoring possible compiler optimizations). Both Objective-C and Smalltalk use a search/hash mechanism to locate class methods, so if you think THIS is slow ...! Keith Gorlen {decvax!}seismo!elsie!cecil!keith -- Keith Gorlen {decvax!}seismo!elsie!cecil!keith
al@ames.UUCP (Al Globus) (10/16/85)
> > Does Objective C provide what Smalltalk calls "blocks"? No. > > Nevertheless, I have two reservations about Objective C. > > (1) If and when someone implements a production-quality > compiler for Smalltalk (incremental compilers already exist), > it seems Objective C will be, in comparison, a less coherent > jumble of two languages. The beauty of Objective C is that it is a nice bridge between current programming practice (in C anyway) and an 'objective future'. You can integrate Objective C into current systems and get a smooth transition. I.e., Objective C is not seen, even by its creators, as the ultimate language, but rather as a useful tool that working programers can use today. I like it, in part, because I can still use all of my C programming chops and I'm in a nice familiar environment, not a complete change as the transition from C to SMALLTALK would be. > > (2) My second reservation is actually a criticism of inheritance > in general. While it is very true that data-abstraction helps > improve the modularity of a program, inheritance requires that > a person trying to implement a particular (sub)class need understand > many, if not all, of the details in its chain of superclasses. > > Rather than subclass to extend the functionality of an object, > I think a more modular approach involves implementing the > extension by USING the original object as part of the "rep". You can use this approach in both SMALLTALK and Objective C, except that you must inherit the properties of the Object class.
richw@ada-uts.UUCP (10/18/85)
al: I called up PPI for Objective C information and they were curious about where I heard about it. Ever consider sales? :-) Concerning inheritance hindering modularity because instance variables are inherited, Keith Gorlen replies: >> This is not necessarily so. In some object-oriented languages (e.g. >> C++) the private instance variables inherited by a subclass are not >> (normally) accessable from the subclass, except via the superclass's >> public methods. Thus, the details of the implementation of a superclass >> chain are just as hidden to the subclass as they are to any user of >> the superclass. Good point. I guess I misjudged inheritance, assuming inst. var.'s HAD to be inherited -- as they say, "I stand corrected". I'm glad that Keith also pointed out that there are least some cases when it's not clear whether subclassing or use of the abstract object is better. This relates to general questions I have about how to really take advantage of inheritance, i.e. I don't know of any attempts at coming up with any well-defined methodology for using it. Can anyone reference anything, or summarize (if it's possible, in 25 words or less) a methodology? For instance, I'd love to learn about ways to really exploit "abstract superclasses" (as defined in the Smalltalk blue-book); the times I have have been pretty fruitful, but I personally felt like I was stumbly in a wilderness... BTW, anybody have any comments about the incongruity where you can "dis-inherit" messages/procedures (by overriding them with procedures that print errors) but cannot dis-inherit instance variables that, in a certain subclass, lose their usefulness? You can actually delay "allocation" of instance variables until you reach the leaves of the class hierarchy, but this leads to a lot of "subclass responsibilities" (as defined in the Smalltalk-80 blue-book), and a lot of confusion. Although I again admit that inheritance CAN be very useful in some circumstances, there have been situations where I've found myself spending more time wondering how to structure the class hierarchy than I spent on getting real work done! As you can tell, I have this love/hate relationship with inheritance... -- Rich Wagner (an instance of the multiply-inherited subclass of Joseph & Christine Wagner)
gww@aphasia.UUCP (George Williams) (10/22/85)
> BTW, anybody have any comments about the incongruity where you can > "dis-inherit" messages/procedures (by overriding > them with procedures that print errors) but cannot dis-inherit > instance variables that, in a certain subclass, lose their usefulness? I don't know SmallTalk, and am not sure what you are asking but... In SIMULA there was(is) a concept of HIDDEN/PROTECTED whereby variables in classes could be hidden from the outside world (as I recall HIDDEN completely hid the variable, and protected marked it as read-only, but I could be wrong). I don't remember how this affected sub-classes, but it would be pretty easy to add something that does...