[comp.object] OOP in C

jokiniem@cs.Helsinki.FI (Jari Jokiniemi) (12/07/89)

We are doing some research on transaction processing on heteroneneous
distributed databases. We have implemented our demo programm using
C language with very conventional programming techniques.

There has been some discussion that one can use object oriented programming
techiques even when writing the programm with any conventional language. Since
the concept of what these OOP techniques really are in practise is not well
explained in any book we've found, the very idea of OOP has remained
fuzzy for us. 

Therefore I ask some help from the netlanders. Would someone
give some examples written in C or some other conventional language 
about what OOP is in practice. We are especially interested in what
data structures are needed, why they are needed, and what benefits may
we gain by using them instead of some other alternatives. We can not
change the programming language, and that is why examples written in C 
would be the ones mostly needed.


-------------------------------------------------------------------------------
Jari Jokiniemi /            / Technical Research Centre of Finland:
              /   OH3BU    /    jjo@tik.vtt.fi                 +358 0 4356 6009
DO IT NOW!   /  HSC 1182  /   University of Helsinki: 
            /            /      jokiniem@cs.Helsinki.FI jokiniemi@finuha.BITNET
-------------------------------------------------------------------------------

mccarrol@topaz.rutgers.edu (Mark C. Carroll <MC>) (12/08/89)

In article <3356@hydra.Helsinki.FI> jokiniem@cs.Helsinki.FI (Jari Jokiniemi) writes:

]We are doing some research on transaction processing on heteroneneous
]distributed databases. We have implemented our demo programm using
]C language with very conventional programming techniques.
]
]There has been some discussion that one can use object oriented programming
]techiques even when writing the programm with any conventional language. Since
]the concept of what these OOP techniques really are in practise is not well
]explained in any book we've found, the very idea of OOP has remained
]fuzzy for us. 
]

I'm going to post another message with a programming project. Before I
do it, I'm going to explain what I mean by OO in my C programming.

To me, the basis of Object Oriented programming as I use it in C
is a sort of excapsulation: I try to hide the internal structure
of my data as much as possible. I define abstract data types by
a set of functions that access them. The actual internal structure
of the data is hidden, in favor of a set of functions that allow
access to the data. 

So, for example, I define a linked list:

typedef void *generic;
typedef int boolean;
typedef struct list_struct {
   struct list_struct *next;
   generic *data;
} *list;

Then, I define the set of structures that are allowed to access my 
list:
list list_New();
boolean list_Insert(generic);/* returns success flag */
boolean list_Remove(generic);
boolean list_Find(generic); 

Now, all access to be lists is done through this set of functions. I
don't ever look at the inside of this structure; I always use this
set of functions. I assume that the list will be homogeneous, or I'd
define a new type for the data field, which had some way of
identifying it's type, and some functions to access that field.

]Therefore I ask some help from the netlanders. Would someone
]give some examples written in C or some other conventional language 
]about what OOP is in practice. We are especially interested in what
]data structures are needed, why they are needed, and what benefits may
]we gain by using them instead of some other alternatives. We can not
]change the programming language, and that is why examples written in C 
]would be the ones mostly needed.
]

I'll post an example of a b-tree assignment I wrote for a class. It's
not a perfect example of thi style, but it should give you an idea.

The advantages of programming this way are:
   + Ease of debugging: when all access to the structure is localized,
    it's much easier to find the bugs. You can be sure of noone mucking
    about with the internal structure of your data.
   + Consistency: you always know exactly how people are going to
    use your code.
   + Reusability: if you keep to a tight, abstract data structure, the
    code for that structure can be used easily in any other program.
   + Organization: I find that code that I write this way is much,
    much easier to read, understand, and debug that code written in a
    less highly structured fashion.
   + discipline: programming this was forces you to be more
    disciplined. You have to clearly think things out in order to
    start writing a program this way.

]Jari Jokiniemi /            / Technical Research Centre of Finland:

	<MC>
-- 
\ Mark Craig Carroll: <MC>          \ "Don't ever think that you can't
 \ Student Systems Programmer - LCSR \  change the past and the future"
  \ Rutgers University                \               -Kate Bush
   \ mccarrol@topaz.rutgers.edu        \ (standard disclaimer applies)

zweig@brutus.cs.uiuc.edu (Johnny Zweig) (12/08/89)

Data encapsulation is one of God's many gifts, but it is not Object-Oriented
Programming.

-Johnny

(P.S. Look in the OOPSLA 86' - '89 proceedings for more info)

hallett@pet16.uucp (Jeff Hallett x5163 ) (12/08/89)

In article <3356@hydra.Helsinki.FI> jokiniem@cs.Helsinki.FI (Jari Jokiniemi) writes:
>
>
>There has been some discussion that one can use object oriented programming
>techiques even when writing the programm with any conventional language. Since
>the concept of what these OOP techniques really are in practise is not well
>explained in any book we've found, the very idea of OOP has remained
>fuzzy for us. 

Since  object-oriented  anything is really  a paradigm,  it should  be
usable  despite   implementation.  However,    certain  implementation
platforms lend themselves to some paradigms better than others.

You can, of course, apply  object-oriented analysis and design to your
system, but  when it comes to  actual implementation, you  will not be
able  to achieve  a pure object-oriented   environment unless everyone
agrees to play by the rules.

It turns out  that just "packaging" your data  structures according to
the standard abstractions (the  linked list is a  classic  example) is
insufficient.   Part  of my   Master's  thesis   was  the design   and
implementation of an  "object-oriented" "language" that was compilable
under  any UNIX-compatible  C compiler (and  would  even compile under
ANSI-compatible compilers).    I quote  "object-oriented"  because  it
didn't have all  the nicities (it did  have dynamic binding of methods
and inheritance at the leaf level, single inheritance, messaging (in a
crude sense) and anonymous creation during loading and storing (a sort
of continuation mechanism, but not a great  one)).  I quote "language"
because it was  really a set of conventions  and predefined structures
and macros that could be compiled under cc.

It  wasn't  great, but   it  did allow  us to write  some fairly large
object-oriented systems using standard  C  compilers with only minimal
difficulty. 

The basic ideas follow:

All instance  variables  and messages are  declared in a  .class file.
Messages are really pointers to functions, as you might expect.

Inside  the class's .c  file, the class struct  is   declared by first
including the superclass' .class file and then its own.  This provides
a simple single inheritance.

The create methods  were recursive - first the  superclass' create  is
called (to initialize  instance variables declared by  the superclass)
and then  the create  codes  specific to this   class is  added.  free
methods were similar.   The  message  slots are filled  with  function
pointers during the create routine - a class may override a superclass
method by simply replacing the  function pointer.  Of course, function
pointers  may be reassigned  at  any time, as   reuqired by the  state
activity of an object.



Of  course, this fixes   the inheritance tree  at compile  time.   The
tricks to achieve posing and  simply continuance  formed the basis for
my  thesis which, unfortunately,  I cannot make generally available at
this time (GE CRD currently has a product involving these techniques).


Maybe this helps, maybe it doesn't. :^)

--
	     Jeffrey A. Hallett, PET Software Engineering
      GE Medical Systems, W641, PO Box 414, Milwaukee, WI  53201
	    (414) 548-5163 : EMAIL -  hallett@gemed.ge.com
		  Est natura hominum novitatis avida

ken@uf.msc.umn.edu (Ken Chin-Purcell) (12/09/89)

In article <3356@hydra.Helsinki.FI>, jokiniem@cs.Helsinki.FI (Jari
Jokiniemi) writes:
> There has been some discussion that one can use object oriented programming
> techiques even when writing the programm with any conventional
language. Since
> the concept of what these OOP techniques really are in practise is not well
> explained in any book we've found, the very idea of OOP has remained
> fuzzy for us. 
> 
> Therefore I ask some help from the netlanders. Would someone
> give some examples written in C or some other conventional language 
> about what OOP is in practice.

I was inspired by a package called "oic" (Objects in C) that was posted
in Macintosh circles about six months ago.  oic was obviously written by
a lisp programmer, and had some nice features.  Unfortunately its method
dispatching took two extra function calls, which I thought to be
too slow for "C" work.  It also looked like it would not port easily
to our Cray.

So I rolled my own :').  "soc" (Simple Object C) implements the object
oriented features found in Object Pascal, simply through style.  For 
cross reference, check out how the X window toolkit implements objects
in C.  As Ralph Swick (of project Athena) said, the X toolkit is
object programming via cut and paste.

Having written widgets, I didn't want to go the cut and paste route,
since it's boring and creates many oportunities for programming errors.
Besides, the X toolkit approach doesn't lend itself to method calls. 

So I used the following strategy: for a new class, define new instance 
variables in the .h file, methods in the .c file.  The .h file #includes
at the end a .oh file, and the .c file #includes a .oc file.  The functions
in the .c file are marked with either "method", to indicate a new method,
or "override" to indicate the redefinition of a superclass's method.
"method" and "override" are #defined to nothing, so the cc compiler ignores
them.  Function names are written as "classname_methodname".

I then wrote a small program, soc, to scan the .c file and write the .oh and
.oc files.  The .oh file defines the class and instance structures
(as structs), and the .oc file initializes the function pointers.  Method calls
are handled by function pointers.  soc also writes out a #define for each
new method.  For example, for the Draw method, first mentioned in class Shape,
the following would be in shape.oh;

	#define _Draw(self)     (*(self)->class->Draw)(self)

We could then later say

	Shape   someKindOfShape;
	_Draw(someKindOfShape);

In essence I have the preprocessor and soc do the cut and paste for me.

To all you I-need-every-feature oop fans:  Yes, I know what I am missing.
However, I have the basic features of Object Pascal, I am writing in C,
I debug the C code I wrote, it works on the Cray, and it's fast.  soc
takes about a second or two to scan and write files on a Sun 3/60.
For now, that's enough :').

If there is any interest out there, I can clean soc up and mail it out.
Just send me a note.

             Ken Chin-Purcell   (aka ken@msc.umn.edu)
                  Minnesota Supercomputer Center

uucibg@swbatl.UUCP (3929) (12/13/89)

In article <1691@mrsvr.UUCP> hallett@gemed.ge.com (Jeffrey A. Hallett (414) 548-5163) writes:
>.............   Part  of my   Master's  thesis   was  the design   and
>implementation of an  "object-oriented" "language" that was compilable
>under  any UNIX-compatible  C compiler (and  would  even compile under
>ANSI-compatible compilers).    I quote  "object-oriented"  because  it
>didn't have all  the nicities (it did  have dynamic binding of methods
>and inheritance at the leaf level, single inheritance, messaging (in a
>crude sense) and anonymous creation during loading and storing (a sort
>of continuation mechanism, but not a great  one)).  I quote "language"
>because it was  really a set of conventions  and predefined structures
>and macros that could be compiled under cc.
>
>It  wasn't  great, but   it  did allow  us to write  some fairly large
>object-oriented systems using standard  C  compilers with only minimal
>difficulty. 
>
>	     Jeffrey A. Hallett, PET Software Engineering
>      GE Medical Systems, W641, PO Box 414, Milwaukee, WI  53201
>	    (414) 548-5163 : EMAIL -  hallett@gemed.ge.com
>		  Est natura hominum novitatis avida

I wrote and have been enhancing (and supporting) something similar for our
work group for the past 6 months.  For those familiar with Objective-C and/or
Complete C, this gives you about 100% the functionality that they do but the
syntax is definitely not as nice.

The system uses a simple front end made up of shell scripts (using sed, egrep,
etc) and some C macros.  It actually sets up the appropriate data structures
as source code so that there is no runtime cost in having the inheritance
hierarchy available.  This also has the down side of not providing runtime
extensibility of objects (something I've been particularly interested in
lately).

It has: (1) single inheritance (I'm working on MI), (2) dynamic message
resolution, (3) IMHO a much easier way of having multiple inheritance
heirarchies (which might be handy if you were developing something embedded
which couldn't carry around all the weight of the standard inheritance
heirarchy).

Becuase it's simple shell scripts and such, it is a bit warty.  However,
I've been toying with the idea of putting it into a Yacc/Bison and Lex/Flex
translator.  I'm particularly interested in perhaps adding: (1) daemons, (2)
more flexible method overriding (e.g. do-after, do-before kinds of things as
apparently exist in Lisp OO systems), (3) method overloading by argument
and/or return types (would probably be better done with a Yacc/Lex xlator),
(4) MI (anyone have pointers to optimization tree searches and or tree
transformations that might be applicable?).

Of course, my employer likes the results we're getting from using an OO
approach, but doesn't want to take the time to properly implement this thing
(or any of the possible extentions). Sigh :-(.


The syntax for defining a class Foo based on class Bar looks like:

@Class  Foo : Bar
	/* Instance variables */
	int	fred;

@InstanceMethods

/* Notice the '#' before the name of the method.
 * Also, Objective-C and Complete C do:
 *
 * - struct fred *myMethod: ( int ) arg1 : ( char * ) arg2 : ( float ) arg3;
 * {
 * ...
 * }
 */
METHOD struct fred *#myMethod( arg1, arg2, arg3 )
int	arg1;
char	*arg2;
float	arg3;
{
	struct	fred	*p;
	int		i;

	/* We have to do 'self->' which Objective-C and Complete-C 
	 * implicitely do for us.
	 */
	self->fred = arg1;

	...

	/* The others let you do i = [ super value ] */
	i = ask( int, super, value, () );
	...

	/* The others let you do p = [ self myMethod: i : (char *)0 : 3.24 ] */
	p = ask( struct fred *, self, myMethod, ( i, (char *) 0, 3.24 ) );
}
	...


@InstanceMethods

	...

@End /* class Foo */



Comments, anyone?

--------------------------------------------------------------------------------
Brian R. Gilstrap    ...!{ texbell, uunet }!swbatl!uucibg OR uucibg@swbatl.UUCP
One Bell Center      +----------------------------------------------------------
Rm 17-G-4            | "Winnie-the-Pooh read the two notices very carefully,
St. Louis, MO 63101  | first from left to right, and afterwards, in case he had
(314) 235-3929       | missed some of it, from right to left."   -- A. A. Milne
--------------------------------------------------------------------------------
Disclaimer:
Me, speak for my company?  You must be joking.  I'm just speaking my mind.

wiseb@turing.cs.rpi.edu (G. Bowden Wise) (12/13/89)

Have you implemented a 'super' construct so that you can override inherited
methods in the derived class and use the super method instead?
************************************************************
* Bowden Wise (wiseb@turing.cs.rpi.edu)                    *
*       RPI Computer Science Department, Troy, NY  12180   *
************************************************************

hallett@pet16.uucp (Jeff Hallett x5163 ) (12/14/89)

In article <G'~M&|@rpi.edu> wiseb@turing.cs.rpi.edu (G. Bowden Wise) writes:
>Have you implemented a 'super' construct so that you can override inherited
>methods in the derived class and use the super method instead?

Yes. Sorta. :^)

Basically, each class we  created also generated  a template which had
default values  for the instance variables  and the methods defined at
that class (or above).

Each new class has a class variable that points to the template of its
superclass.  So,   if  a class  needs  to  use   all  or part   of its
superclass's methods, it executes the ones from the template.


--
	     Jeffrey A. Hallett, PET Software Engineering
      GE Medical Systems, W641, PO Box 414, Milwaukee, WI  53201
	    (414) 548-5163 : EMAIL -  hallett@gemed.ge.com
		  Est natura hominum novitatis avida

uucibg@swbatl.UUCP (3929) (12/14/89)

In article <G'~M&|@rpi.edu> wiseb@turing.cs.rpi.edu (G. Bowden Wise) writes:
>Have you implemented a 'super' construct so that you can override inherited
>methods in the derived class and use the super method instead?
>************************************************************
>* Bowden Wise (wiseb@turing.cs.rpi.edu)                    *
>*       RPI Computer Science Department, Troy, NY  12180   *
>************************************************************

Yes.  IMHO, It would be a pretty brain-dead OOP system if it didn't have
this.  In Coo (the origins of the name I'm trying to lose into the mists
of time :-), you would invoke use the 'super' construct inside a method via:

    ...
    something = ask( int, super, doSomethingWhichReturnsIntVal, ( myArg ) );
    ...

This does what you expect (if you are familiar with Objective-C, Complete C,
etc).  Basically, it starts the search for the method with the super-class 
methods of the current object.  Er, let's try that again.  If I use super in
a method of class Foo and Foo's super-class is Bar, then the search for
method "doSomethingWhichReturnsIntVal" will start with the methods of class
Bar.


Thanks,
--------------------------------------------------------------------------------
Brian R. Gilstrap    ...!{ texbell, uunet }!swbatl!uucibg OR uucibg@swbatl.UUCP
One Bell Center      +----------------------------------------------------------
Rm 17-G-4            | "Winnie-the-Pooh read the two notices very carefully,
St. Louis, MO 63101  | first from left to right, and afterwards, in case he had
(314) 235-3929       | missed some of it, from right to left."   -- A. A. Milne
--------------------------------------------------------------------------------
Disclaimer:
Me, speak for my company?  You must be joking.  I'm just speaking my mind.

sasdjb@sas.UUCP (David Biesack) (12/20/89)

I'm surprised nobody has mentioned Class, the oo preprocessor with which
the Andrew system was developed at CMU. It supports single inheritance,
overrides, and super methods. Class is fairly easy to use; I developed
(yet-another) widget class hierarchy using it and had very few problems.
It's not as full-fledged as C++, though, but it gets the job done.

Class runs as a preprocessing step on a .H file which contains class
declarations. This generates two include files, one #included for
users of the class, one #include'd for the implementation of
the methods. Except for the .H file, everything is standard C.
Even the method "renaming" is usable, and debugging was straight forward.

I haven't tried to use Class outside of the Andrew system, so I don't 
know how general purpose it is. Integrated with the Andrew system, the
object code was dynamically loaded, so the first instantiation of a
class instance loaded the class methods. My guess is that this behavior
could be extracted out of the Class system (it may not actually be part
of what Class does, anyway.) Anyone from CMU ITC know the answer?

Class comes on the X Window System tape (X11R3) somewhere in the
bowels of the contrib directory. The preprocessor is actually a very small
C program (about 1000 lines, if I recall).

djb

-- 

David J. Biesack	SAS Institute, Inc.   
rti!sas!sasdjb 		SAS Circle, Box 8000  
(919) 467-8000 		Cary, NC 27512-8000