[comp.object] Evaluating "Object-Oriented" Progra

johnson@p.cs.uiuc.edu (01/09/90)

I'm always happy to see a long article from Ed Berard, and this one is
no exception.  However, there were quite a few things that I disagreed
with in this article.

First, a matter of history.  Simula was the first OOP language.  It is
true that Smalltalk advanced the state of the art quite a bit, and that
most Americans learned of OOP because of Smalltalk, and that Smalltalk
is quite a bit different from Simula.  However, we should keep our history
straight.

In my opinion, the three major characteristics of an OOP language are

1. data abstraction
2. inheritance
3. polymorphism caused by late-binding of procedure calls

I've never been able to understand why information hiding isn't just
an aspect of data abstraction.  I also think that data abstraction
and abstract data types are synonyms, but maybe I'm just stupid.

Note that 3) is broad enough to encompass CLOS generic functions
and C++ virtual functions, and that class are nowhere mentioned.
Ada falls down on both 2) and 3), because overloading is NOT
late-binding nor, in my opinion, true polymorphism.

I also take issue with the claim that Smalltalk is less polymorphic
than ML.  If you have a type system for Smalltalk, which I do, then
you will see that Smalltalk programs can do all the tricks of ML,
and then a bunch more.  In fact, languages like Eiffel or Trellis/Owl
have type systems that are as polymorphic as ML.  The thing that is
so great about ML is that it has a complete type inference algorithm,
not that it is the end-all and be-all of polymorphism.

In my opinion, type-checking is completely orthoganal to whether a
language is OOP or not, and adding type-checking to Smalltalk does
not make it more of an OOP language.

Snorri Agnarsson said some good things about automatic memory management,
all of which I support.  It might be possible to think that he implied that
memory management is a feature of object-oriented programming.  Someone
famous in the Smalltalk community (Dan Ingalls?) said this.  However, I
don't agree at all.  Automatic garbage collection is wonderful, and it
is especially useful in writing reusable code, but it is orthoganal to
OOP.

I also agree with the claim that Snorri (or someone else) made that
late-binding is more important than inheritance.  I think I've said
that in public before.  Of course, I wouldn't want to give up inheritance.

If anybody wants a reference to my definition of OOP languages, I gave it
in "Designing Reusable Classes" with Brian Foote in the 2 issue of the
Journal of Object-Oriented Programming.  (The June/July 88 issue, I think).
I'll send copies of the paper to people who can't find copies of the journal.

Ralph Johnson -- University of Illinois at Urbana-Champaign

susser@apple.com (Joshua Susser) (01/10/90)

In article <135300019@p.cs.uiuc.edu> johnson@p.cs.uiuc.edu writes:
> In my opinion, the three major characteristics of an OOP language are
> 
> 1. data abstraction
> 2. inheritance
> 3. polymorphism caused by late-binding of procedure calls
> ...
> Snorri Agnarsson said some good things about automatic memory management,
> all of which I support. It might be possible to think that he implied that
> memory management is a feature of object-oriented programming.  Someone
> famous in the Smalltalk community (Dan Ingalls?) said this.  However, I
> don't agree at all.  Automatic garbage collection is wonderful, and it
> is especially useful in writing reusable code, but it is orthoganal to
> OOP.

Not quite.

Characteristic 1) (which I generally refer to as encapsulation) implies
garbage collection in a rather straightforward manner.  Since an object
encapsulates its state, once you give it a reference to another object,
say as an argument to a message, you have no way of knowing whether that
reference is maintained or not.  From then on you can never externally
know if it is okay to free the referenced (second) object.  And if that
object is ever referenced by more than one object, you have to be able to
look inside all possible referents to know if the object can be reclaimed.
The general case of this is called garbage collection.

Joshua Susser                                            Apple Computer ,Inc.
Object Percussionist                                Advanced Technology Group
arpa: susser@apple.com                            20525 Mariani Ave. MS 76-2D
uucp: {backbone}!apple!susser                             Cupertino, CA 95014
ALink: susser.j                                                  408/974-6997

"I beat on objects."

pallas@Neon.Stanford.EDU (Joe Pallas) (01/10/90)

In article <135300019@p.cs.uiuc.edu> johnson@p.cs.uiuc.edu writes:

>In my opinion, the three major characteristics of an OOP language are

>1. data abstraction
>2. inheritance
>3. polymorphism caused by late-binding of procedure calls

Okay, that looks like a subset of my list, which appears below.

>I've never been able to understand why information hiding isn't just
>an aspect of data abstraction.  

I think this is a common point of miscommunication.  Many people
(perhaps most) treat protection or privacy as part of data
abstraction.  I prefer to make a distinction between abstraction as
voluntary and protection or privacy as involuntary.  For example, it
isn't hard to do data abstraction in C using structs, but it is
impossible to enforce protection.  Likewise, in Ada, you can choose
whether or not your data type is private, but your client can choose
to treat it abstractly even if it isn't private.

>I also think that data abstraction
>and abstract data types are synonyms, but maybe I'm just stupid.

This may not be presented very well, but here's my view on that (and
my list):

1) Data abstraction is a property of a language,
	abstract data types are things in the language/implementation.

2) Protection is a property of a language,
	messages are things in the language/implementation.
	(in my view, messages are things which explicitly
	cross protection boundaries, like protected procedure calls)

3) Bundling code and data together is a property of a language,
	objects are things in the language/implementation.

4) Universal polymorphism is a property of a language,
	run-time types are things in the language/implementation.

5) Inheritance is a property of a language,
	inheritance hierarchies are things in the language/implementation.

As far as the list itself goes, many people combine (1) and (2).
Various people call (2) or (3) or both ``encapsulation'', so I have
given up on that word.  Some people feel (5) is not necessary; I
believe that (4) without (5) is not very useful.

I'd be interested in comments on either my property-of/thing-in
approach or the list itself.

joe

johnson@p.cs.uiuc.edu (01/15/90)

Markku Sakkinen wrote:
>Question: However, isn't it actually bogus that all fundamental things
>in _Smalltalk_ are first-class objects? For instance, how do you define
>a use a meaningful subclass of SmallInteger, adding at least one
>instance variable?

SmallIntegers are implemented by a hack (use of a tag bit) so, as far as
I know, none of the Smalltalks let you subclass SmallInteger.  However,
this is not a problem in practice, since it is easy to subclass Integer,
and all you have to do is make a new kind of Integer whose value is a
SmallInteger and that delegates a few important operations (+,-,/,*,<,=)
to its value.  Such a subclass will work like a SmallInteger and you can
easily add new methods or variables to it without interfering with
regular SmallIntegers.

This is an extreme example of a general property of inheritance: it is
usually a lot cleaner to inherit from abstract classes than from concrete
classes.  It is quite common for a subclass to need a different data
representation, but inheritance brings along the superclass's data
representation.  

Ralph Johnson

sakkinen@tukki.jyu.fi (Markku Sakkinen) (01/15/90)

In article <135300024@p.cs.uiuc.edu> johnson@p.cs.uiuc.edu writes:
>
>Markku Sakkinen wrote:
>>Question: However, isn't it actually bogus that all fundamental things
>>in _Smalltalk_ are first-class objects? For instance, how do you define
>>a use a meaningful subclass of SmallInteger, adding at least one
>>instance variable?
>
>SmallIntegers are implemented by a hack (use of a tag bit) so, as far as
>I know, none of the Smalltalks let you subclass SmallInteger.  However,
>this is not a problem in practice, since it is easy to subclass Integer,
>and all you have to do is make a new kind of Integer whose value is a
>SmallInteger and that delegates a few important operations (+,-,/,*,<,=)
>to its value.  Such a subclass will work like a SmallInteger and you can
>easily add new methods or variables to it without interfering with
>regular SmallIntegers.
>
>This is an extreme example of a general property of inheritance: it is
>usually a lot cleaner to inherit from abstract classes than from concrete
>classes.  It is quite common for a subclass to need a different data
>representation, but inheritance brings along the superclass's data
>representation.  

Thank you for the information. However, the main reason why instances
of the basic atomic classes of Smalltalk don't look like first-class objects
to me is that they are immutable (while instances of normal classes
are mutable) and they can be neither created (thus there can be no
initialisation methods) nor deleted, at least conceptually.

In contrast, if the programmer defines a subclass, say MyInteger (concrete),
of the abstract class Integer, then instances of MyInteger are entirely
ordinary objects; they will obey "reference semantics" instead of the
"value semantics" of built-in integer types. As an example, suppose
some method of class Car contains
   price <- anotherCar price
If the price object is a MyInteger, this assignment will cause sharing,
quite unlike ordinary integers.

So it seems unwise to define any subclasses of Integer and similar
built-in classes: they might cause unpleasant surprises to users later.
This holds for type-checking derivatives of Smalltalk (see e.g. Johnson's
paper from OOPSLA'86) as well, since MyInteger _is_ formally a subclass
of Integer.

Disclaimer (again): because of no practical experience with Smalltalk,
the above may be incorrect in technical details.

Markku Sakkinen
Department of Computer Science
University of Jyvaskyla (a's with umlauts)
Seminaarinkatu 15
SF-40100 Jyvaskyla (umlauts again)
Finland

pallas@Neon.Stanford.EDU (Joe Pallas) (01/17/90)

In article <2704@tukki.jyu.fi> sakkinen@tukki.jyu.fi (Markku Sakkinen) writes:

>However, the main reason why instances
>of the basic atomic classes of Smalltalk don't look like first-class objects
>to me is that they are immutable (while instances of normal classes
>are mutable) ...

Instances of ``normal classes'' are only mutable if they have instance
variables.  Classes with no instance variables (and, hence, immutable
instances) may not be common, but they are both possible and useful.
(Example: Booleans)

>... and they can be neither created (thus there can be no
>initialisation methods) nor deleted, at least conceptually.

On the contrary, conceptually they are created and deleted [whatever
that means with GC] all the time.  It's the implementation that does
not actually create and destroy them, for efficiency's sake.  The
implementation can do that precisely because it makes no difference at
the user level.

As an exercise, try to write a Smalltalk expression (without using
explicit identity tests) that will yield different results when a and
b are the same instance of such a class and when they are different
instances of such a class.  It's not hard to see that if there are no
instance variables, all instances have the same behavior (excepting
explicit identity tests, which most implementations do not allow to be
redefined).  And, logically, if they always behave the same you can't
tell them apart.

joe