[net.lang.c] Object Programing and Objective C

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...