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!