[comp.sw.components] What is a reusable software compone

johnson@m.cs.uiuc.edu (07/28/90)

I think that Paul Sander's B-tree abstraction is a pretty good
reusable component.  However, I think that Bill Ogden has a
good point.  Bill's basic point is that it is really more
important to reuse specifications than it is to reuse
implementations.  Of course, we need to provide implementations
for our specifications, but the user should think mostly of the
specification and not the implementation.  B-trees are an
implementation, while almost-constant functions are specification.

Further, I take the point of view held by the object-oriented
community that it is not particular kinds of components that are
important, but rather sets of components and their relationships.
The advantage of concentrating on specification is that you end
up with lots of components that share the same specification.
When you learn one, you have learned something about all of them.
Also, it becomes easier to replace one component with another
because they will share specification.  Thus, it becomes easier
to write utilities that work with any of the related components.

This is not all that relevant to Paul's original article, but I
saw a soapbox, and couldn't resist getting on it.

Ralph Johnson -- University of Illinois at Urbana-Champaign

rick@.tetrauk.UUCP (Rick Jones) (07/30/90)

In article <71800004@m.cs.uiuc.edu> johnson@m.cs.uiuc.edu (Ralph Johnson)
writes:
>
>I think that Paul Sander's B-tree abstraction is a pretty good
>reusable component.  However, I think that Bill Ogden has a
>good point.  Bill's basic point is that it is really more
>important to reuse specifications than it is to reuse
>implementations.  Of course, we need to provide implementations
>for our specifications, but the user should think mostly of the
>specification and not the implementation.  B-trees are an
>implementation, while almost-constant functions are specification.
>
>Further, I take the point of view held by the object-oriented
>community that it is not particular kinds of components that are
>important, but rather sets of components and their relationships.
>The advantage of concentrating on specification is that you end
>up with lots of components that share the same specification.
>When you learn one, you have learned something about all of them.
>Also, it becomes easier to replace one component with another
>because they will share specification.  Thus, it becomes easier
>to write utilities that work with any of the related components.

I see this as the key difference between the OO concept of re-use, and the
procedural library approach.  In both cases, software is certainly re-used, but
the whole OO thing is really about specification and design.

OO languages provide a way of moving from the design stage to the coding stage
without the sort of traumatic paradigm shift which results in design
information getting lost.  Further, OO encourages _design_ re-use as much as
code re-use.  Abstract classes provide one means to do this, so that you can
have an abstract structure (B-tree or whatever else you want), and different
implementations inheriting from it.  The program components which use the
structure can use the abstract type, except where the structure is actually
created, which is where the decision has to be made;  this should only be at
one place.  If you decide to use a different implementation of the structure,
you should only need to change about one line of code.

The other important re-use issue is partial re-use.  You have a component which
is nearly what you want, but you need a few variations for your application.
This is what inheritance can give you.  This leads into a problem which I don't
think is resolved, or even fully understood, regarding what you actually
inherit.  Is it an abstraction (i.e. a consistent interface) or an
implementation (i.e. some useful chunks of code)?  A statically type-checked
language assumes and/or requires descendant classes to conform to their
parents;  but do you always want that?  It sounds like a good case for dynamic
type checking (Smalltalk and Objective-C users can afford to smirk here :-).
	[ Extended discussion of inheritance aborted - please pick it up if
	  you're interested. ]

Although you can take a very object-oriented approach to software with a
standard procedural language, careful design, and good coding discipline, the
concepts of abstract types and re-use by inheritance really require a true
object-oriented language to make them work for you.

I find it helps to think of programs as recipes rather than actual components.
There will be a recipe in the library for a plain cake.  If you want to write a
recipe for a fruit cake, you just write "Proceed as for a plain cake, but add a
handful of fruit in the final mixing" (this is not a recommendation for my
cakes!).  You "inherit" the plain cake recipe from the library, and produce a
descendant recipe.  This will create a different object, and it is the
_objects_ which are the "components";  they are created at run-time and behave
according to their class descriptions (i.e. the programs).  You don't make a
good fruit cake by buying a plain cake from the shop and then trying to stuff
fruit into it when you get home.

In summary, I believe it's better to treat software as detailed component
designs, rather than actual components, and thus software re-use _is_ design
and specification re-use.  The major benefit of object-oriented languages, and
the way of thinking which they (should) promote, is to bring the ideas of
"design" and "code" closer together so that they can be treated as different
levels of the same thing.

-- 
Rick Jones					You gotta stand for something
Tetra Ltd.  Maidenhead, Berks			Or you'll fall for anything
rick@tetrauk.uucp (...!ukc!tetrauk.uucp!rick)	     - John Cougar Mellencamp

johnson@m.cs.uiuc.edu (08/01/90)

Paul Sander writes:
>I was under the impression that a major reason for inventing reusable
>components was to reuse code, that is to recycle implementations.
Certainly.  However, it turns out that you get better code reuse
when you think about standardizing specifications.  Futher, you can't
reuse code as often as you can reuse design.

Paul and I seem to have a different definition of specification.
A specification does not have to define a complete behavior for a
component.  In fact, the most useful specifications are incomplete.
Most components that meet a particular specification will in fact
meet much more detailed specifications as well.

I agree that it isn't crucial that we have many implementations of
specifications such as almost-constant-functions.  However, it is a
good idea to have many implementations of specifications such as
displayable objects.  It is important that all displayable objects
conform to a standard interface so that programs can manipulate images
without having to worry about their complexity.

Like I said,
>>Further, I take the point of view held by the object-oriented
>>community that it is not particular kinds of components that are
>>important, but rather sets of components and their relationships.
>>The advantage of concentrating on specification is that you end
>>up with lots of components that share the same specification.
>>When you learn one, you have learned something about all of them.
>>Also, it becomes easier to replace one component with another
>>because they will share specification.  Thus, it becomes easier
>>to write utilities that work with any of the related components.

Perhaps if you replace "specification" with "interface" then you
will understand my point better.  I believe that there is no real
difference in the terms.

I've been building object-oriented systems for a few years now.
Inheritance is nice, and I don't want to do without it, but
polymorphism is more important.  Polymorphism depends on a set
of different classes that all meet the same specification.

>In practice while programming, it turns out that the interfaces of the
>two objects may be the same, but the objects are hardly interchangeable,
>since their semantics are different.  They may not even be compatible in
>the sense that one can replace the other in some section of code.

Suppose I give the specification that a program must halt with the
variable X equal to 1.  There are lots of different programs that
meet this specification, and they are not interchangeable, unless
that is all we care about.  A summation routine only cares that its
arguments have an addition operation, but the routine that calls it
may also want the sum of two polynomials to be a polynomial.  There
is no contradiction.

Ralph Johnson -- University of Illinois at Urbana-Champaign