[comp.lang.c++] oo definition request

shirley@uiucdcsm.cs.uiuc.edu (05/11/88)

I would like people to give their MINIMAL definitions of 'object
oriented programming'.  Also, what MUST a language  be to be called
an 'oo language'.  Please also state the reference, if any, that 
gave/influenced your definition.


Thanks,

Peter Shirley
U of Illinois at CU

dan@Apple.COM (Dan Allen) (05/12/88)

Peter Wegner's paper presented at OOPSLA 87 (entitled "Dimensions of
Object-Based Language Design") had this formula:

	object oriented = objects + classes + inheritance.

Using this as a definition excludes Ada, Modula-2, and other languages
that DO support abstract data types.  For Wegner, if fields of an object
can be accessed directly (like fields in a record), it was
object-oriented, but if fields of an object can only be accessed through
function calls to an object's methods, then it supported data
abstraction.  I do not know what he would say about C++ in specific
which supports EITHER paradigm, or a mix of them, as Wegner made this
distinction an orthogonal distinction.

In light of all this, I would say that his definition is still a fair
one.  I would be very curious to hear what Stroustrup would have to say
about this formulaic definition.

Dan Allen
Software Explorer
Apple Computer

bs@alice.UUCP (05/12/88)

Dan Allen frompple Computer Inc, Cupertino, CA writes

 > Peter Wegner's paper presented at OOPSLA 87 (entitled "Dimensions of
 > Object-Based Language Design") had this formula:

 > 	object oriented = objects + classes + inheritance.

 > Using this as a definition excludes Ada, Modula-2, and other languages
 > that DO support abstract data types.  For Wegner, if fields of an object
 > can be accessed directly (like fields in a record), it was
 > object-oriented, but if fields of an object can only be accessed through
 > function calls to an object's methods, then it supported data
 > abstraction.  I do not know what he would say about C++ in specific
 > which supports EITHER paradigm, or a mix of them, as Wegner made this
 > distinction an orthogonal distinction.

This is an easy one. I was there. Wegner specifically mentioned C++ as one
of the two languages that supports BOTH abstract data types and object-oriented
programming (the other was DEC's experimental system/language Trellis/Owl).
It is just a pity he didn't WRITE that too.

 > In light of all this, I would say that his definition is still a fair
 > one.  I would be very curious to hear what Stroustrup would have to say
 > about this formulaic definition.

About the best you can do on one line. Defining a popular word such as
``object-oriented'' is confounded with many practical difficulties. For
example, I don't really think you could find agreement on a single
PRECISE definition of the words ``object'', ``class'', and ``inheritance''
acros the specter of languages to which they could reasonably be applied.
acros the specter of languages to which they could reasonably be applied.

My two bits on the confused subject of ``What is Object-Oriented Programming?''
can be found in my paper with that title in this month's issue of IEEE
Software. It is also in the Santa Fe proceedings.

rickers@drexel.UUCP (Rick Wargo) (05/14/88)

From article <4800021@uiucdcsm>, by shirley@uiucdcsm.cs.uiuc.edu:
> I would like people to give their MINIMAL definitions of 'object
> oriented programming'.  Also, what MUST a language  be to be called
> an 'oo language'.  Please also state the reference, if any, that 
> gave/influenced your definition.
> 
> Peter Shirley
> U of Illinois at CU

Byte Magazine, Volume 11, Number 8 (August 1986) had an article
written by Geoffrey Pascoe of DoD Computing Systems Research Division (MD) 
entitled "elements of Object-Oriented Programming."  In this article
he states that there are four (and possibly five) qualities a language
should exhibit to be considered object oriented.

    1) information hiding
       - insures reliability of software
       - reduces inter-dependencies
       - state of a software module contained in private
         variables, accessible from only within the scope
         of the module
       - most languages support information hiding, for example,
         static variables in functions in C
    2) data abstraction
       - programmer defines an abstract data type which consists of an
         internal representation and a set of routines to access and
         manipulate the data
    3) dynamic binding
       - poly-morphism - the same message can elicit a different response
         depending on receiver, this should be accomplished at run-time.
       - no need to modify existing code
    4) inheritance
       - sub and super classing
    5) and, automatic storage management
       - better know as garbage collection
       - should qualify as fifth important element

							Rickers
							..!drexel!rickers

P.S.  This is an excerpt from the notes of an informal class on object-
oriented programming which I had taught last year.

jima@hplsla.HP.COM ( Jim Adcock) (05/17/88)

|    5) and, automatic storage management
|       - better know as garbage collection
|       - should qualify as fifth important element

Garbage collection seems to conflict with the needs of many "real-time"
programs.  So if one took "garbage collection" as a requirement
for OOP, then you'd be excluding OOP from many "real-time" applications.
So I don't buy item #5.

Maybe #5 could be rephased more generally as:

5) and, concepts for storage management.

Then C++ would still qualify [and should qualify, I believe, because I
believe C++ gives you the tools necessary to do a good job of storage
management]

Maybe "garbage collection" could be handled as a standard C++ "base-class"
that interested users could inherit off of, without the whole C++ community
having to buy into this overhead.  Still, I have a hard time believing that
a large portion of the C++ community could agree on one common approach
to garbage collection that would meet all their needs.  Which would
counter-indicate even a standard "garbage collected" class.

So far, any project that I have seen that makes extensive use of garbage
collection "everywhere" runs slow enough to be of marginal utility.
 

johnson@uiucdcsp.cs.uiuc.edu (05/18/88)

I consider the three key features of o-o programming to be
data abstraction, late-bound procedure calls (messages) and inheritance.
My definition of data abstraction is less strong than Wegner's since
anything he calls an object I would probably consider a data abstraction,
i.e. it is not necessary to avoid all direct references to the fields of
an object.  Instead, an object is something with a state and a set of
operations.

grogers@uiucdcsm.cs.uiuc.edu (05/19/88)

This is not short but here goes.  [And please don't comment on my notation,
I'm just making it up as I go along.]

It seems to me that the key requirement for object-oriented programming is that
a program must always present the illusion that an object's state can only
be changed by the object itself and the object does so in response to messages
it receives from other objects.

Given this requirement it is possible to write in an oo style within a non-oo
language (pascal).  However, it is also possible to cheat.  An oo language
enforces the style and does not allow cheating.  This is similar to structured
programming through careful use of gotos or through enforced use of
if-then-else, for, while....

I disagree with the Wegner definition, since the object's state can be
manipulated independently of the object.  (e.g.  obj->state = newvalue).
The problem with this is that the object does not know that it has changed
and cannot notify any other objects that may be interested in that change nor
can it perform value validity checking.  (e.g. A text object should be
redisplayed if it changes or an array index should not be out of bounds.)
You might say that the "=" is not assignment but a message that is sent to
the object.  Fine, but then the program does not have direct access to the
object's state and that's not what Wegner said.

One aspect of oo programming that complicates things is the question of
whether classes should be first class objects.  If so, their instance variables
and methods can change (both value and existence) during the execution of the
program.  Now we cannot allow direct access to the instance variables of an
object because these may not exist at some point in the program lifetime.
An example:

	Class C {
		instance vars: a, b, c;
		class vars: x, y, z;
		methods:
		...
	}

	aC isa Class newInstance;
	aC.a = 5;
	C removeInstanceVar "a";
	aC.a = 6;

The last statement must fail because the instance variable no longer exists.
This can only be done by late binding.  I admit that this example is somewhat
far fetched, but I can also imagine of creating or destroying a method for
writing an object to disk.  If the write method does not exist, the object is
for read only use.


Next issue: inheritance.
The major advantage of inheritance is improved code reuse.  I contend that
in the absence of classes as first class objects inheritance only
provides code reuse.  The function of the class could be replicated in each
of the subclasses and the subclass would not behave differently (of course,
there must still be only one set of class instance variables).  I'm not
advocating this, since unless it's completely automatic the superclass copies
will diverge as the subclasses are modified.

Inheritance also provides a good mechanism for deriving abstract data types.
"Subclass A is just like its superclass B except for ...."  Unfortunately,
sometimes the subclass is more general and sometimes more specific.  Although
this is necessary it can be confusing.  With inheritance, only the "except
fors" need be stated. Without, class A must explicitly define a method, say X,
and explicitly pass control flow, "A.X: y { self B.X: y }" [the notation is:
receiverObject Class.Method: params] for each method it wants to inherit.


It seems to me that an interesting question is: what's the difference between
abstract data type programming and object oriented programming?

I would say that the primary difference is polymorphism.  Historically
speaking, adts have been implemented as hidden data areas with access functions.
Thus, each data type has a set of specific functions for accessing the adt's
data.  For example: stack_insert( s, item) and queue_insert( q, item).
While oo programming assumes polymorphism as implemented through message
passing.  So here we have: s insert: item and q insert: item.  It is the object
that determines which "insert" method is executed rather than the invoker.
This has a major impact on the code that is written.  In an adt language
we would have 
	switch (type_of X)
	case sphere: 
		sphere_render( X, PHONG );
	case nurb: 
		nurb_render( X, PHONG );
	... all other cases...

an oo language would have the switch implicit in the method lookup
and so we just need
	X render: PHONG


While I do think that inheritance and memory management are very useful and
should be part of any programming environment, I don't think they are
necessary for oo programming.


So, what do you think?

Greg Rogers
University of Illinois at Urbana-Champaign
Department of Computer Science
1304 W. Springfield Ave.
Urbana, IL 61801

(217) 333-6174

	UUCP:	{pur-ee,convex,inhp4}!uiucdcs!grogers
	ARPA:	grogers@a.cs.uiuc.edu
	CSNET:	grogers%uiuc@csnet-relay

db@its63b.ed.ac.uk (D Berry) (05/20/88)

In article <4800024@uiucdcsm> grogers@uiucdcsm.cs.uiuc.edu writes:
>
> I disagree with the Wegner definition, since the object's state can be
> manipulated independently of the object.

You also disagree with him in that you think inheritance isn't necessary.

> The major advantage of inheritance is improved code reuse.  I contend that
> in the absence of classes as first class objects inheritance only
> provides code reuse.

I agree.  Code reuse is important, but I believe it's possible to gain the
same effect as inheritance with subtyping and "traditional" scope management.

> It seems to me that an interesting question is: what's the difference between
> abstract data type programming and object oriented programming? I would say
> that the primary difference is polymorphism.  Historically speaking, adts have
> been implemented as hidden data areas with access functions.
>
> Thus, each data type has a set of specific functions for accessing the adt's
> data.  For example: stack_insert( s, item) and queue_insert( q, item).  While
> oo programming assumes polymorphism as implemented through message passing.
> So here we have: s insert: item and q insert: item.  It is the object
> that determines which "insert" method is executed rather than the invoker.

This is not polymorphism; it's overloading function names (and probably dynamic
binding).  A polymorphic function can be applied to an argument of any type
(perhaps of any type in a certain set, but certainly more than one).
Overloading a function name gives you a similar interface, but has one function
for each type.

For example, in ML all lists must contain objects of a single type and the
function "hd" has the type 'a list -> 'a, which means it can be applied to any
list and returns an object of the same type as the objects in the list (it
actually returns the head object of the list).  Thus it is polymorphic.

On the other hand, both "2 + 1" and "2.5 + 1.5" call a function named "+",
but the first calls an integer version and the second a float version.  (In
fact these are defined in their own structures, which are the nearest
equivalent in ML to classes.)

Polymorphism and overloading are similar but different.  The choice obviously
affects code size; it also affects type inference for those languages which
have it.

If ML had subtyping, it might be possible to define polymorphic functions
that would work on objects of a certain type and its subtypes, but not on all
types.  This is similar to inheriatnce in oo langauges.  However, to get
different behaviour for a subclass the function name would have to be
overloaded for that subclass (and often a dynamic binding scheme would have to
be used).

Note: if a language has functions as first class objects then subtyping
is quite different from inheritance.  For example, if "integer" is a subtype
of "real", then a class comprising a function of type "int -> int" could be a
subtype of a class comprising a function "int -> real", but the type makes no
restriction on what the function actually is - for one object of that type the
function could be factorial, for another it could be successor, for a third it
could be abs_value.

The distinction between inheritance and subtyping is similar to the
distinction between polymorphism and overloading.  Inherited functions are
defined for each class rather than for each object, object-oriented
notation notwithstanding.

> While I do think that inheritance and memory management are very useful and
> should be part of any programming environment, I don't think they are
> necessary for oo programming.

I agree (at least for the present).  Consider removing inheritance from
SmallTalk.  Would the result still be object-oriented?  I think so - 
everything in the system would still be an object and evaluation would
still be done by passing messages.

> Greg Rogers
-- 
-------------------------------------------------------------------------------
 Dave Berry.	db%lfcs.ed.ac.uk@nss.cs.ucl.ac.uk	Free jazz, not markets

johnson@uiucdcsp.cs.uiuc.edu (05/24/88)

A polymorphic procedure is one that takes arguments of many different
types.  There are several different kinds of polymorphism.  ML features
"parametric" polymorphism. (I hope I get all these names right.)  C++
features "inclusive" polymorphism, where an instance of a subclass can
be treated as if it were in a superclass.  A type system for Smalltalk
would have to treat "ad-hoc" polymorphism, which is where unrelated
objects can all implement the same operation, but in entirely different
ways.  The question, "Which is more important in an object-oriented
programming language, inheritance or message-passing?" is the same as
saying "Which kind of polymorphism is most important, inclusive or ad-hoc"?

Languages like Trellis/Owl show that ad-hoc polymorphism can be
translated into inclusive polymorphism with multiple inheritance.
If a procedure needs to be able to operate on objects in class A or
class B then you can just define a common superclass to describe
their commonality.  On the other hand, parametric polymorphism is
still needed even if the other two are allowed.

For further information, see the paper by Cardelli and Wegner in
Computing Surveys a few years ago.

db@its63b.ed.ac.uk (D Berry) (06/01/88)

In article <77300011@uiucdcsp> johnson@uiucdcsp.cs.uiuc.edu writes:
>
>A polymorphic procedure is one that takes arguments of many different
>types.  There are several different kinds of polymorphism.  ML features
>"parametric" polymorphism. (I hope I get all these names right.)  C++
>features "inclusive" polymorphism, where an instance of a subclass can
>be treated as if it were in a superclass.  A type system for Smalltalk
>would have to treat "ad-hoc" polymorphism, which is where unrelated
>objects can all implement the same operation, but in entirely different
>ways.

C++ also allows ad-hoc polymorphism (a.k.a. overloading), by allowing
redefinition of members in subclasses.  Most object-oriented languages do this.

It's easy to confuse inclusive polymorphism with subtyping.  A function
is polymorphic if it operates on a variety of types.  When members are
redefined then we also have overloading, even if functions are only
redefined in subclasses (subtypes) of a given class.
Another way of looking at this is to say that when a member is
redefined, it only inherits the type of the corresponding member in
the superclass, not the definition.

Note 1: I'm disagreeing with Cardelli & Wegner here.  They (to my mind)
	confuse inheritance and subtyping.
Note 2: C++ also has pure overloading, though that's not relevant here.

>Languages like Trellis/Owl show that ad-hoc polymorphism can be
>translated into inclusive polymorphism with multiple inheritance.
>If a procedure needs to be able to operate on objects in class A or
>class B then you can just define a common superclass to describe
>their commonality.

You can describe the fact that they each have a member of a certain name,
but the actual functions are still different.  Thus you still have
ad-hoc polymorphism (as above).

The languages I've seen with multiple inheritance require each class
to specify their superclasses.  This means that if overloading
(ad-hoc polymorphism) is "replaced by multiple inheritance", every case
of overloading must be anticipated by the program or library developer.

Does Trellis/Owl have this restriction?  Or does it allow a programmer
to specify existing classes as subclasses of a new class?  Presumably
this would require either:

  1. a dynamic programming environment to modify the original classes or
  2. fairly tight restrictions on such a scheme, such as requiring every
     specified subclass to override every public member of the new superclass,
     so that the new superclass would essentially exist only for type-checking.

>The question, "Which is more important in an object-oriented
>programming language, inheritance or message-passing?" is the same as
>saying "Which kind of polymorphism is most important, inclusive or ad-hoc"?
>
>For further information, see the paper by Cardelli and Wegner in
>Computing Surveys a few years ago.

1985, pp.471-522.

On p.477 the authors write:
	"... ad-hoc polymorphism is some kind of _apparent_
	 polymorphism whose polymorphic character disappears
	 at close range."
This is why I prefer the term "overloading" to "ad-hoc polymorphism",
since it stresses the distinction between a polymorphic function and
a group of functions with the same name (and possibly the same type).
-- 
-------------------------------------------------------------------------------
 Dave Berry.	db%lfcs.ed.ac.uk@nss.cs.ucl.ac.uk	Free jazz, not markets

johnson@uiucdcsp.cs.uiuc.edu (06/02/88)

>C++ also allows ad-hoc polymorphism (a.k.a. overloading), by allowing
>redefinition of members in subclasses. Most object-oriented languages do this.

This is not ad-hoc polymorphism.  This is inclusive polymorphism.
Imagine that each object has a field for each of its member functions.
This field contains the function.  While this is not the way C++ is
implemented, it is clearly the way you are supposed to think that it
is implemented, since x.foo() means extract the "foo" field of "x"
and call it.   The variable "x" can contain any subclass of the type
of "x", so this seems to be inclusive polymorphism.

Smalltalk has ad-hoc polymorphism because the variable "x" could have
contained any object that implements the "foo" operation, even if they
belonged to wildly different classes.  The critic could claim that this
is really a form of inclusive polymorphism that is hidden by the fact
that Smalltalk is not statically type-checked.

>It's easy to confuse inclusive polymorphism with subtyping.

I thought Cardelli and Wegner defined inclusive polymorphism to be
equivalent with subtyping?  I think by subtyping you mean subclassing.
It is easy to confuse subclassing with subtyping.  :-)  I have a type
system for Smalltalk in which subclasses are not subtypes.  However,
C++, Trellis/Owl, and Eiffel make them be the same, so lots of people
think that they have to be the same.  Emerald has subtypes but no
inheritance, so there is a little more evidence that subtypes are
not subclasses.  The type of X is a subtype of Y if X can always be
treated as a Y.  Thus, subtypes deal with specification.  Inheritance
deals with implementation.  Naturally, implementation and specification
should be related, which is why so many languages make subclasses be
the same as subtypes, but there is no reason why they HAVE to be
equivalent.

>When members are
>redefined then we also have overloading, even if functions are only
>redefined in subclasses (subtypes) of a given class.
>Another way of looking at this is to say that when a member is
>redefined, it only inherits the type of the corresponding member in
>the superclass, not the definition.

I agree completely.  In fact, in Smalltalk it is not necessary for a
method in a subclass to inherit its type from the superclass, which is 
why subclasses in Smalltalk are not subclasses.  However, inclusive
polymorphism does not prevent functions from being redefined.  It just
says that redefined functions must have types that are compatible with
those of the methods being redefined.

>The languages I've seen with multiple inheritance require each class
>to specify their superclasses.  This means that if overloading
>(ad-hoc polymorphism) is "replaced by multiple inheritance", every case
>of overloading must be anticipated by the program or library developer.

>Does Trellis/Owl have this restriction?  Or does it allow a programmer
>to specify existing classes as subclasses of a new class?

Overloading does not have to be anticipated by the program developer,
but shared interfaces do.  Suppose that I have a graphical object
that is composed of lots of other graphical objects.  I implement
operations to read and write the array that holds these graphical
objects, which in Smalltalk would be at: and at:put:.  Now suppose
that I have a sort routine, which takes an array and a predicate
which imposes a total ordering on the object in the array.  In
Smalltalk I can use that sort routine (which I imagine here to be
an object rather than a method) to sort the graphical objects, since
all it requires is that its input understand the at: and at:put:
messages.  In C++, on the other hand, this graphical object will
have to be a subclass of "Array", but I want it to be a subclass
of "GraphicalObject".  Thus, I need multiple inheritance to make
it be a subclass of both.  Multiple inheritance is not needed as
much in Smalltalk.  It would be needed if you wanted the complex
graphical object to understand ALL the array messages, but it
seems unnecessary if all you need are at: and at:put:.  However,
a language with static type-checking requires multiple inheritance.

I am not knocking static type-checking.  It makes it much easier to
create fast implementations, and languages like C++ are certainly a
lot faster than languages like Smalltalk.  However, you do lose a
bit of flexibility.  Most people are probably willing to pay the
price, but I want to have my cake and eat it, too!