[comp.sw.components] Reasons for low reuse

billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 ) (09/05/89)

   On the subject of why reuse does not take place more frequently,
   the article appearing just before the one Scott cited ("Can Programmers
   Reuse Software?" IEEE Software, July '87, pp. 52-60) comments:

      If the worth of reusing an ADT could be accurately assessed,
      we would expect a person to reuse an ADT even if only a few
      percent of the creation effort could be saved... Software
      development personnel untrained in software reuse are 
      influenced by some unimportant features [of a component]
      and are not influenced by some important ones... users
      cannot properly assess the worth of reusing a candidate
      ADT...       

   Also, regarding the hardware analogy, it does not draw a direct
   correspondence between computer software and computer hardware;
   rather, it draws an analogy to the extensive catalogs of ICs, 
   resistors, capacitors, etc. used by electrical engineers to build
   all kinds of application-specific products.   It seeks to diminish 
   the "art form" mindset, replacing it with "engineering discipline".


   Bill Wolfe, wtwolfe@hubcap.clemson.edu
 

scotth@boulder.Colorado.EDU (Scott Henninger) (09/05/89)

|>From: billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 )
|Subject: Re: Reasons for low reuse
|Date: 5 Sep 89 01:21:47 GMT
|
| ("Can Programmers Reuse Software?" IEEE Software, July '87, pp. 52-60)
 
So we must ask ourslves - Do we want to "train" people to become successful
reusers, or should we provide adequate support for reusing software.  It is not
clear to me that all of the training in the world will solve the problem.  The
problem is twofold (maybe more):  First of all, there are potentially millions
of components to choose from.  No one could possibly keep track of all of them.
Support for retrieving useful components is therefore needed.  Secondly, once
you've got a component, you must tailor it to your specific needs.  This means
understanding the code or some description of the code.  Anyone who has debugged
code written by others can attest to just how difficult this is.  The
"conceptual closeness" measures devised by Prieto-Diaz are a first step in
trying to assess the modifiability of a component.  One could also argue that
conceptual level (as opposed to implementation level) descriptions are needed
(no, current documentation techniques are not sufficient).

|   Also, regarding the hardware analogy, it does not draw a direct
|   correspondence between computer software and computer hardware;
|   rather, it draws an analogy to the extensive catalogs of ICs, 
|   resistors, capacitors, etc. used by electrical engineers to build
|   all kinds of application-specific products.

Again, this assumes that the components can be used without modification.  This
is not the norm with software, but is with hardware.  Also, we must keep in mind
that resistors and capacitors implement one kind of machine.  For software, we
must find the equivalents of resistors and capacitors for each domain we write
software for.

|   It seeks to diminish the "art form" mindset, replacing it with "engineering
|   discipline".  

To claim that this is true is to claim that all the world's domains can be
reduced to engineering principles.  While it's a worthy goal, I'm not so sure
that it can be done.

I would like to hear other opinions.  Anyone out there?
-- Scott
   scotth@boulder.colorado.edu

uucibg@swbatl.UUCP (3929) (09/06/89)

In article <11347@boulder.Colorado.EDU> scotth@boulder.Colorado.EDU (Scott Henninger) writes:
>|   Also, regarding the hardware analogy, it does not draw a direct
>|   correspondence between computer software and computer hardware;
>|   rather, it draws an analogy to the extensive catalogs of ICs, 
>|   resistors, capacitors, etc. used by electrical engineers to build
>|   all kinds of application-specific products.
>
>Again, this assumes that the components can be used without modification.  This
>is not the norm with software, but is with hardware.  Also, we must keep in mind
>that resistors and capacitors implement one kind of machine.  For software, we
>must find the equivalents of resistors and capacitors for each domain we write
>software for.
>
>|   It seeks to diminish the "art form" mindset, replacing it with "engineering
>|   discipline".  
>
>To claim that this is true is to claim that all the world's domains can be
>reduced to engineering principles.  While it's a worthy goal, I'm not so sure
>that it can be done.
>
>I would like to hear other opinions.  Anyone out there?
>-- Scott
>   scotth@boulder.colorado.edu

I think I'm probably jumping in way over my head here, but I'll hazard a very
naive opinion... :-).

It would seem to me that the hardware analogy is actually rather appropriate.
But before anyone goes and rants all over me, think about how many engineers
we have out there.  Obviously, "engineering" is still an art too.  Namely, it
is the art of examinging a body of solutions to previous problems and trying
to find one or more solutions which can be adapted to solve the current
problem.  I don't see any way to claim that this isn't still an art, since
we would have replaced all those engineers with computers if it weren't an
art.

This makes me believe that there will always be a certain art to software
development.  I would never claim that engineers are not in some sense of the
word artists.  In this respect, software component development seems to have
two major fronts:

1) coming up with better techniques for identifying commonality between problems
(and therefore their solutions).  This is perhaps as much a "way of thinking"
task as it is an infrastructure development task.  Not to say that there isn't
a *lot* of infrastructure that we can develop.  Quite the contrary, I would
agree with previous statments that software component technologies are rather
embryonic (lots of room for fortunes to be made.... :-).

2) Convince the world (through case studies) that reuse can save them time and
dollars.  This is the only thing that will convince the "suits" that this
wonderful infrastructure is worth paying for and worth the cost of retraining
their people to use.

If this is all very obvious to everyone, sorry...

Thanks,
--------------------------------------------------------------------------------
Brian R. Gilstrap    ...!{ {killer,bellcore}!texbell, uunet }!swbatl!uucibg
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.

billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 ) (09/06/89)

From scotth@boulder.Colorado.EDU (Scott Henninger):
> | ("Can Programmers Reuse Software?" IEEE Software, July '87, pp. 52-60)
>  
> [...] It is not clear to me that all of the training in the world will 
> solve the problem.  The problem is twofold (maybe more):  First of all, 
> there are potentially millions of components to choose from.  [...] 

   The first problem that has to be overcome is the Not Invented
   Here syndrome; we must have programmers who want to use components.
   This can be addressed by training (at the university level), and
   also by appeal to management (in the "real world").  Incidentally, 
   the hardware analogy is absolutely wonderful for convincing 
   non-technical managers of the value of reuse; they grasp it
   instantly, and immediately become enthusiastic supporters.

> Secondly, once you've got a component, you must tailor it to your 
> specific needs.  This means understanding the code or some description 
> of the code.  Anyone who has debugged code written by others can attest 
> to just how difficult this is.  

   Wonderful reasons for NOT DOING IT!!!  In particular, components
   should be designed in a generic manner, such that the "customization"
   can be done automatically.  As an example, I manage the Clemson Ada
   Software Repository, which contains ADTs like Generic_Priority_Queue 
   (among others).  The user can dream up a new data type, define a few
   simple operations over the type (such as "=" and assignment), write
   a single line of code to do the instantiation, and voila: the user 
   now has a new data type (a priority queue which can manage objects 
   of the user's new type), and a considerable range of powerful 
   operations over that queue, without ever looking at anyone else's 
   implementation code; the entire process takes a grand total of 
   about 5 minutes.
 
> |   Also, regarding the hardware analogy, it does not draw a direct
> |   correspondence between computer software and computer hardware;
> |   rather, it draws an analogy to the extensive catalogs of ICs, 
> |   resistors, capacitors, etc. used by electrical engineers to build
> |   all kinds of application-specific products.
> 
> Again, this assumes that the components can be used without modification.
> This is not the norm with software, but is with hardware.  Also, we must 
> keep in mind that resistors and capacitors implement one kind of machine.
> For software, we must find the equivalents of resistors and capacitors for
> each domain we write software for.

   Resistors and capacitors are domain-independent, and so it is with
   abstract data types such as B+ trees, linked lists, directed graphs,
   etc.; these are the resistors and capacitors of the software profession.

   There are also special-purpose ICs in the hardware industry, and 
   these are the things which must be developed according to the methods 
   described by Guillermo Arango in his brilliant article on Domain Analysis.
   The software equivalent of a special-purpose IC would be a package 
   containing a set of domain-specific data types, functions, and procedures.   


   Bill Wolfe, wtwolfe@hubcap.clemson.edu

billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 ) (09/06/89)

From article <765@swbatl.UUCP>, by uucibg@swbatl.UUCP (3929):
> Obviously, "engineering" is still an art too.  Namely, it is the art of 
> examining a body of solutions to previous problems and trying to find one
> or more solutions which can be adapted to solve the current problem.  I 
> don't see any way to claim that this isn't still an art, since we would 
> have replaced all those engineers with computers if it weren't an art.

   There is a general progression which all fields go through:

     Art form  =>  Engineering discipline  =>  Hard Science

   The progress along this route is proportional to what is known
   about the field.  The continuum indicates the progression from
   all heuristics (toward the left) to all deterministic solutions
   (toward the right); the fields which fall in between the two
   extremes are those for which heuristics are used to fill in the
   areas in which there still is not sufficient science.

   When a field is referred to as an engineering discipline, it means that 
   informal heuristics are on the way to becoming an endangered species, 
   and the software field is progressing very quickly in that direction.


   Bill Wolfe, wtwolfe@hubcap.clemson.edu

nagle@well.UUCP (John Nagle) (09/07/89)

      The "reuse" concept is fundamentally flawed.  Software components are
not "reused", they are "used".  This is to say that good software components are
not leftovers from past projects, but units designed from the beginning to be
components.  They are productized, documented, and sold as components.

      There is a small but successful industry selling software components
for microcomputers.  Graphics packaged, database management packages,
and communications packages seem to be the most common offerings.

      Having used a few of these products, my main observation is that
using software components from multiple vendors tends to result in
annoying problems.  A typical problem stems from several components
assuming that they can safely replace some standard portion of the
standard C library (such as "printf" or "exit") with their own version.
This is a good reason for only buying components for which one gets
source code, so that such problems can be resolved.

      Another problem is incompatibility of components with new releases
of other tools.  When a new release of a C compiler comes out, it seems
to be necessary, annoyingly, to upgrade some components at the same time.
This can create problems, since the upgraded components may not be available
for some time after the release of the compiler.  Operating system releases
can cause similar trouble.  This can be a serious problem; in the worst case,
dependence on a software component which is not being upgraded can result
in the inability to continue work on a program.

					John Nagle

scotth@boulder.Colorado.EDU (Scott Henninger) (09/08/89)

|>From: billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 )
|
|   The first problem that has to be overcome is the Not Invented
|   Here syndrome; we must have programmers who want to use components.
|   This can be addressed by training (at the university level), and
|   also by appeal to management (in the "real world").  

To say this is to say that current reuse environments are adequate.  They
are not.  The fact of the matter is that it is easier and takes less time
to code it yourself than reuse existing code with current technology. 
Besides, and I repeat, *people are not aware of what reusable components
exist*.  This is primarily a tools problem, not a training problem. 
Training can only get you so far.  Supporting tools must exist before
people will practice what they are preached.

It should also be noted that the NIH syndrome exists in any design
discipline.  To paraphrase Herbert Simon: "when designing artifacts for
people, *do not postulate a new man*".  The NIH syndrome is simply a part
of human nature.  You, President Bush, or anyone else, ARE NOT GOING TO
CHANGE IT.  Claiming that the "the problem has to be overcome" in this
case makes the critical mistake of trying to change human nature.

|> Secondly, once you've got a component, you must tailor it to your 
|> specific needs.  This means understanding the code or some description 
|> of the code.  Anyone who has debugged code written by others can attest 
|> to just how difficult this is.  
|
|
|   Wonderful reasons for NOT DOING IT!!!  In particular, components
|   should be designed in a generic manner, such that the "customization"
|   can be done automatically.  

Unfortunately, this is a yet unrealized goal.  The fact of the
matter is that designing generic code is extermely difficult and time
consuming.  And it will NEVER be able to handle all of the cases that
programmers will come up with.  The ability to tailor existing code is
essential. 

|   As an example, I manage the Clemson Ada
|   Software Repository, which contains ADTs like Generic_Priority_Queue 
|   (among others).  The user can dream up a new data type, define a few
|   simple operations over the type (such as "=" and assignment), write
|   a single line of code to do the instantiation, and voila: the user 
|   now has a new data type (a priority queue which can manage objects 
|   of the user's new type), and a considerable range of powerful 
|   operations over that queue, without ever looking at anyone else's 
|   implementation code; the entire process takes a grand total of 
|   about 5 minutes.

This is precisely my point.  Whenever people talk about generic code, they
inevitably give examples of *simple* ADTs; ones that you learn in your
freshman programming class.  I would argue that this would constitute an
extermely small percentage of the code for, say, an accounting program, a
user interface, or microcode for a tape drive.  The extreme effort
expended in creating a generic stack, queue, or whatever brings little
savings to one trying to create a real application.


|   There are also special-purpose ICs in the hardware industry, and 
|   these are the things which must be developed according to the methods 
|   described by Guillermo Arango in his brilliant article on Domain Analysis.
|   The software equivalent of a special-purpose IC would be a package 
|   containing a set of domain-specific data types, functions, and procedures.   

I agree with this in principle.  What we have to avoid is making the
arrogant statement that Computer Science will give us the ability to
formalize all domains; i.e. succeed where others have been "failing" for
tens, hundreds or thousands of years (all the way back to Plato). 
Guillermo's approach of "controlled approximations to *satisfycing*
solutions" is exactly what I'm arguing for.

Let me make a clarifying remark.  I have always stated that the hardware
analogy is *misleading* and is doing a great deal of harm to current thinking
about software reuse.  There are surface similarities, but the problem is
much greater for software.  A hardware engineer can flip through a few
hundred pages of hardware component descriptions and find what he needs. 
Because software is so much more diverse than hardware, the number of
potential components increases by orders of magnitude.  This makes the
problem *fundamentally* different - tools are needed to assist the
programmer.



-- Scott
   scotth@boulder.colorado.edu

ram@wb1.cs.cmu.edu (Rob MacLachlan) (09/09/89)

>From: billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 )
>Subject: Re: Reasons for low reuse
>Date: 5 Sep 89 21:40:24 GMT
>
>   There is a general progression which all fields go through:
>
>     Art form  =>  Engineering discipline  =>  Hard Science
>
>   The progress along this route is proportional to what is known
>   about the field.  

This is a ridiculously sweeping generalization, and also one pretty
discredited in philosophy-of-science circles.  This "physics envy" has been
a justification for much bad science (e.g. behaviorism.)

As to the hardware analogy, I am not surprised non-technical managers find
it seductive: oversimplifications usually are.  It does show that it would
be *nice* to have standard software components, but it doesn't show that it
is possible.  

There is an illusory similarity because the analogy compares *computer*
hardware and *computer* software.  You could have said:
    "It takes only 47 kinds of screws to build an automobile, so we should
     be able to make do with 47 sofware components."

But of course, that would sound silly...

  Rob

brucec@demiurge.WV.TEK.COM (Bruce Cohen;685-2439;61-028) (09/09/89)

In article <11449@boulder.Colorado.EDU> scotth@boulder.Colorado.EDU (Scott Henninger) writes:
>Let me make a clarifying remark.  I have always stated that the hardware
>analogy is *misleading* and is doing a great deal of harm to current thinking
>about software reuse.  There are surface similarities, but the problem is
>much greater for software.  A hardware engineer can flip through a few
>hundred pages of hardware component descriptions and find what he needs. 
>Because software is so much more diverse than hardware, the number of
>potential components increases by orders of magnitude.  This makes the
>problem *fundamentally* different - tools are needed to assist the
>programmer.
>
There is another reason why the hardware problem is simpler than the
software: the hardware domain has been deliberately restricted to make
standard components easy to specify.  It's taken many years, but we
have arrived at the point where any new family of components MUST adhere to
a set of standard interfaces (five volt power supply, high-true logic,
standard logic level voltage minima and maxima, etc., etc.  Standardizing
packages has enforced constraints on the partitioning of hardware systems
(if you have only 40 pins, you can't transfer 200 signals directly).  And
the maximum manufacturable number of logic gates on a chip at a given time
places a limit on what a designer will attempt on one chip; software size
limitations are much more elastic.

Beyond these standardizations is another one: most hardware designs these
days are for digital transformers: widgets which take in a set of digital
signals and put out another set in response.  Market conditions typically
dictate things like timing requirements, word size, etc.  Similar
constraints on software are again less demanding: ASCII for character
representation does not really restrict the input much since there are so
many possible meaningful combinations of characters in any useful input
language.

>-- Scott
>   scotth@boulder.colorado.edu

"Men in padded bras don't look the same falling from high places."
    - R.A. McAvoy - "The Third Eagle"

Bruce Cohen
brucec@orca.wv.tek.com
Interactive Technologies Division, Tektronix, Inc.
M/S 61-028, P.O. Box 1000, Wilsonville, OR  97070

billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 ) (09/10/89)

From article <13499@well.UUCP>, by nagle@well.UUCP (John Nagle):
>       Having used a few of these products, my main observation is that
> using software components from multiple vendors tends to result in
> annoying problems.  A typical problem stems from several components
> assuming that they can safely replace some standard portion of the
> standard C library (such as "printf" or "exit") with their own version.
> This is a good reason for only buying components for which one gets
> source code, so that such problems can be resolved.

    Alternatively, you can use a language whose designers recognized
    the need for portability; Ada prohibits subsets and supersets, and
    issues validation certificates to compilers only after they have
    passed a rigorous validation suite; even then, the certificate is
    only good for about 18 months, at which point the compiler must face
    a newer, stronger validation suite if it is to obtain a new certificate.


    Bill Wolfe, wtwolfe@hubcap.clemson.edu

billwolf%hazel.cs.clemson.edu@hubcap.clemson.edu (William Thomas Wolfe, 2847 ) (09/10/89)

From scotth@boulder.Colorado.EDU (Scott Henninger):
> To say this is to say that current reuse environments are adequate.  They
> are not.  The fact of the matter is that it is easier and takes less time
> to code it yourself than reuse existing code with current technology. 

   Not true; the work required to repeat the design, implementation,
   and testing of a component is considerable.  Furthermore, the 
   component's implementation is likely to be considerably more 
   sophisticated than the probable result of an attempt to do it
   from scratch.   

> Besides, and I repeat, *people are not aware of what reusable components
> exist*.  This is primarily a tools problem, not a training problem. 

   My perspective is that if the market exists (i.e., if people are
   looking for components and wishing for better tools), the tools
   will spring up to meet the demand.  Where people don't bother to
   look, the tools aren't going to appear courtesy of the Tool Fairy.

> The NIH syndrome is simply a part of human nature.  

   There are a great many cultures throughout the world which practice
   ideas which appear to be alien from the perspectives of other cultures.
   This does not imply that a baby from one of those other cultures could 
   not be socialized into such a culture, such that the ostensibly alien 
   practices seem perfectly natural.  Hence, I suggest that professional 
   training can be designed such that practices are internalized which 
   preclude the possibility of rejecting an idea on the basis of its origin.
 
> designing generic code is extermely difficult and time consuming.  

   The engineering of ANY product is usually difficult and time-consuming,
   especially given that the designer of a generic component is trying to
   ensure a great many things that the user doesn't even know s/he needs.
   As a simple example, suppose that a user takes a component and uses it
   in a sequential application.  Later, the application is maintained such
   that multitasking is introduced.  Fortunately, the component's designer
   implemented the component such that multiple requests can be processed
   in parallel, while still maintaining serializability and recoverability.

   This demonstrates that the benefits of using a component can extend far
   beyond the initial construction of the application.  Such an application
   will probably be of considerably higher quality than a corresponding 
   application which did not make use of sophisticated software components.
 
> And it will NEVER be able to handle all of the cases that programmers 
> will come up with.  The ability to tailor existing code is essential. 

   Given the existence of a highly sophisticated component, any user who
   tries to modify it will probably only get into trouble.  It's much 
   better to use the component in the implementation of a higher-level 
   user-defined interface than to try to modify a component's implementation.
 
> Whenever people talk about generic code, they inevitably give examples 
> of *simple* ADTs; ones that you learn in your freshman programming class.
> I would argue that this would constitute an extermely small percentage of
> the code for, say, an accounting program, a user interface, or microcode
> for a tape drive.  

   Domain-specific components will come with their own abstract data types,
   and will normally make considerable use of those types in the supplied
   procedures and functions.  While it is certainly conceivable that 
   generic parameters would prove useful in situations in which the
   domain-specific processing is performed on arbitrary data types,
   or using arbitrary user-defined procedures or functions, the fact
   that generic code is much more vital to the area of "container" ADTs 
   has resulted in a short-term concentration of interest in that area. 
   
   Also, some of the situations you describe are ones in which a different
   technique is applicable: packaging.  An abstract interface will be 
   constructed (e.g., a standard CRT (or CPU) interface), and the
   implementation of that package will translate those commands into 
   whatever is necessary to implement them on a given hardware system.  
   When porting the application it is only necessary to rewrite the 
   machine-dependent parts of the system, which will have been segregated 
   into the bodies of specific packages.  The protection provided by the 
   package specification will ensure that the rest of the application 
   will remain unaffected. 

> Because software is so much more diverse than hardware, the number of
> potential components increases by orders of magnitude.  This makes the
> problem *fundamentally* different - tools are needed to assist the
> programmer.

   Tools *are* needed, but they won't sell if there isn't enough demand!! 
   If organizations can be convinced to commit to a reuse program, then
   the tools will quickly follow.  


   Bill Wolfe, wtwolfe@hubcap.clemson.edu

grichard@skiff.cis.ohio-state.edu (Golden Richard) (09/10/89)

Another (perhaps secondary) reason that I see for the current "low reuse"
syndrome is the number of extremely sloppy components that are available.
While working on a project at the University of New Orleans, we decided
to "save time" and purchase a number of C components from a company in
New Jersey (whose name I should actually mention, but I won't).   To make
a long story short, some of the development ended up taking 10X longer than
if we had simply written everything ourselves.   Bugs started to creep in
and workarounds sometimes took days.  

I'm all for reusable software components, but some reasonably formal system
of specifying *exactly* what the components do and a verification method
for providing better than "a 50-50 chance" of the components meeting specs
are absolutely necessary.   A major problem with using someone
else's code in object form is that, barring a rigorous specification, it's 
virtually impossible to ascertain *exactly* what a component does.   Having
source is helpful, but who wants to poke through hundreds (thousands?) of
pages of code "verifying" functionality?



-=-
Golden Richard III        OSU Department of Computer and Information Science
grichard@cis.ohio-state.edu         "I'm absolutely positive!  ...or not."    

simpson@trwarcadia.uucp (Scott Simpson) (09/12/89)

In article <60116@tut.cis.ohio-state.edu> Golden Richard <grichard@cis.ohio-state.edu> writes:
>I'm all for reusable software components, but some reasonably formal system
>of specifying *exactly* what the components do and a verification method
>for providing better than "a 50-50 chance" of the components meeting specs
>are absolutely necessary.   A major problem with using someone
>else's code in object form is that, barring a rigorous specification, it's 
>virtually impossible to ascertain *exactly* what a component does.

I've been reading Bertrand Meyer's book, and one of the ways Eiffel
enforces correctness is by specifying semantic assertions that must be
met by routines in a class.  Eiffel uses preconditions (require),
postconditions (ensure) and class invariants (invariant).
Preconditions and postconditions must only be met at the beginning and
end of a routine.  Class invariants must be met at all "stable" times
(between routine calls).  If you don't meet an assertion, an exception
is raised.  Also, hiers to a class must meet all the assertions of its
parent, so you can't change behavior by inheriting.  For example, the
ADT for a stack may look like (this is not Eiffel, just an ADT spec)


	TYPES			-- Syntax
		STACK[X]	-- Generic stack with type X
	FUNCTIONS		-- Syntax
		empty: STACK[X] -> BOOLEAN  --Accessor function. Stack on left
		new: -> STACK[X]	    --Creation function. Stack on right
		push: X x STACK[X] -> STACK[X] --Transformer function.
					       --Stack on both sides.
		pop: STACK[X] /-> STACK[X]      --Transformer. /-> denotes
						--partial function. I.e., 
						--function doesn't work for
						--all values (like stack
						--empty)
		top: STACK[X] /-> X	    --Accessor
	PRECONDITIONS		-- Semantics.  Clarifies partial functions.
		pre pop(s:STACK[X]) = (not empty(s))
		pre top(s:STACK[X]) = (not empty(s))
	AXIOMS			-- Semantics
		For all x:X, s:STACK[X]:
		empty(new())
		not empty(push(x,s))
		top(push(x,s))=x
		pop(push(x,s))=s
	
There is a lot of information there that specifies exactly how a stack
behaves.  You can model virtually all of this in Eiffel.

Here is an Eiffel implementation:

class STACK[T] 
export
	push, pop, top, empty, nb_elements, empty, full -- What clients can see
feature
	implementation: ARRAY[T];
	max_size: INTEGER;
	nb_elements: INTEGER;

	Create(n:Integer) is 
		-- Allocate stack for maximum of n elements
		-- (or for no elements if n < 0)
	do
		if n>0 then max_size := n end;
		implementation.Create(1, max_size)
	end; -- Create

	empty : BOOLEAN is
		-- Is stack empty?
	do
		Result := (nb_elements = 0)
	end; -- empty

	full : BOOLEAN is
		-- Is stack full?
	do
		Result ;= (nb_elements = max_size)
	end; -- full
	
	pop is
		-- Remove top element
	require		-- Precondition!
		not empty	-- i.e. nb_elements > 0
	do
		nb_elements := nb_elements - 1
	ensure		-- Postcondition!
		not full;
		nb_elements = old nb_elements - 1
	end; -- pop

	top : T is
		-- Top element
	require
		not empty -- i.e. nb_elements > 0
	do
		Result := implementation.entry(nb_elements)
	end; -- top

	push(x : T) is
		-- Add x on top
	require
		not full -- i.e. nb_elements<array_size in this representation
	do
		nb_elements := nb_elements + 1;
		implementation.enter(nb_elements, x)
	ensure
		not empty;
		top = x;
		nb_elements = old nb_elements + 1
	end; -- push

invariant	-- These always must satisfied at stable states.
	0 <= nb_elements; nb_elements <= max_size;
	empty = (nb_elements = 0)
end -- class STACK

The only AXIOM that is not ensured by this code is 

	pop(push(x,s)) = s

so you can see that enforcing correctness can be facilitated by the use
of assertions.
	Scott Simpson
	TRW Space and Defense Sector
	usc!trwarcadia!simpson  	(UUCP)
	trwarcadia!simpson@usc.edu	(Internet)

garym@ulysses.UUCP (Gary Murphy) (09/12/89)

In article <60116@tut.cis.ohio-state.edu> Golden Richard <grichard@cis.ohio-state.edu> writes:
>Another (perhaps secondary) reason that I see for the current "low reuse"
>syndrome is the number of extremely sloppy components that are available.
>...[an example of buying object code] ... A major problem with using someone
>else's code in object form is that, barring a rigorous specification, it's 
>virtually impossible to ascertain *exactly* what a component does.   Having
>source is helpful, but who wants to poke through hundreds (thousands?) of
>pages of code "verifying" functionality?

I've had similar experiences with C library functions packaged with a
compiler, with 3rd party code that uses 'slightly' variant library
functions, and some OOP systems where the interface is formally spelled
out but the rest kept elsewhere - in all three cases, I've either needed
to hunt down the real source or waste a great deal of time probing a
black box.

In this day and age, few programmers would even poke through the lines
they wrote themselves without a symbolic debugger and if source is included,
all it takes is a single re-compile to create the step-able version.

And speaking of reuse, and this problem of source-code secrets, how does
this sit with the misplaced metaphor of software-as-literature with respect
to copyrights? (If I quote Tolstoy's first edition, and the passage is
stated contrarily in the fifth, do I still owe royalties? :-).
-- 
     Gary Murphy - Cognos Incorporated - (613) 738-1338 x5537    
  3755 Riverside Dr - P.O. Box 9707 - Ottawa Ont - CANADA K1G 3N3
          e-mail: decvax!utzoo!dciem!nrcaer!cognos!garym         
  Cosmic Irreversibility: 1 pot T -> 1 pot P, 1 pot P /-> 1 pot T

dwiggins@atsun.a-t.com (Don Dwiggins) (09/13/89)

Being real process-oriented lately, I'd like to put this reuse discussion in
a broader setting.  Many assertions have been made about the possibilities
and issues of reuse, each based on unstated or only partially stated
assumptions about the process and setting of the supposed act of reuse.  In
fact, there can be many such settings, each implying different constraints
and characteristics of the components, the collection of them, and the
"reuser".  For example,

    The personal toolkit: an experienced machanic collects high-quality
    tools, assumes responsibility for them, and takes them with him/her.
    Having created a module to solve a problem, an experienced software
    engineer might well generalize the solution a bit, polish the
    implementation and the interface description, and drop it in the kit.

    The corporate resource: rather than continually reinventing solutions to
    recurring problems, the company creates a library and supporting staff
    to capture the solutions and make them available to new projects.  Note
    that there's likely some domain leverage here; the company's projects
    will often cover a lot of the same ground.

    The commercial product: this is what seems to have been the assumption
    behind most of the discussions so far.  Even here, there are many
    possible relationships among the component and library creators,
    sellers, and buyers, and probably many possible types of "component"
    (how about selling detailed designs or generic sources like MacApp?)

In all these settings, I think that the major problems are organizational,
psychological, and institutional -- meeting the differing goals of the
various folks involved.  It'll probably take some "process prototyping" to
work these out.  The technical problems that arise will be solved as part of
all this (and some technical issues will turn out to be non-problems).

What I'd like to see is some reuse success and horror stories along this
line: what was the setting and process, how did it work out, what problems
arose and how were they solved (if they were)?


--
Don Dwiggins				"Solvitur Ambulando"
Ashton-Tate, Inc.
dwiggins@ashtate.uucp

hopper@ntmtv.UUCP (Ian Hopper) (09/13/89)

I have always felt that some form of Garbage Collection is
needed in order to do a decent job on reusable "Collection"
modules.  Since the current favorite language (C++) does
not consistiently (or easily) support GC, we do not see
good quality collection modules.

I believe the Smalltalk books come to the same conclusion, but
neither Smalltalk nor it's creators are perfect.

The classic approach would be to copy-in and copy-out the contents
of such containers, but simply passing pointers to contents is
often much faster.

Do we focus our efforts on languages that have garbage collection,
or are we forced to use the copy-in/copy-out approach?  Regrettably,
the USING code is quite different in the various cases.

Looking forward to responses,
	-- Ian Hopper

PS: Writers of collection modules in GC-based environments should
not forget to create dynamically-expanding versions of their collections.
It is very annoying to have to estimate the size of collections in
advance, things always blow up on large data sets.

scotth@boulder.Colorado.EDU (Scott Henninger) (09/16/89)

|>From: hopper@ntmtv.UUCP (Ian Hopper)
|
|I have always felt that some form of Garbage Collection is
|needed in order to do a decent job on reusable "Collection"
|modules.  Since the current favorite language (C++) does
|not consistiently (or easily) support GC, we do not see
|good quality collection modules.

Quality in what sense? Program efficiency? Cognitive efficiency (i.e. how
readable it is)? Correctness? Reliability?




-- Scott
   scotth@boulder.colorado.edu

ram@wb1.cs.cmu.edu (Rob MacLachlan) (09/18/89)

>From: hopper@ntmtv.UUCP (Ian Hopper)
>Newsgroups: comp.sw.components
>Subject: Re: Reasons for low reuse
>Date: 13 Sep 89 03:43:32 GMT
>
>I have always felt that some form of Garbage Collection is
>needed in order to do a decent job on reusable "Collection"
>modules.
[...]
>
>The classic approach would be to copy-in and copy-out the contents
>of such containers, but simply passing pointers to contents is
>often much faster.
>
>Do we focus our efforts on languages that have garbage collection,
>or are we forced to use the copy-in/copy-out approach?  Regrettably,
>the USING code is quite different in the various cases.

It seems to me that once you admit dynamic allocation into the language, one
must at least concede the \desirability/ of having GC.  The only question is
whether the cost of supporting GC is excessive.  There are two costs that I
see:
 1] A performance penalty due to GC time and tag manipulation.  Unless GC
    support is controlled by a compiler switch, some of this overhead is also
    present in programs that don't use GC.  GC can also cause unpredicable
    delays.
 2] At the language level, a certain discipline in pointer use is required
    so that the garbage collector can locate pointers and not be confused by
    random data that might be a pointer.  

Being a Lisp programmer, it is understandable that I don't find either of
these costs prohibitive.  The performance penalty isn't as much as people
suppose: a lot of progress has been made in GC algorithms in the past ten
years, and these algorithms have recently begun to see practical use in
languages such as Lisp, Smalltalk and ML.  Also, as you hinted at above,
there are often hidden efficiencies that can only be safely realized in
systems that support GC.  So far as the language style issue, this isn't a
big problem for high-level languages other than C.

I think that Lisp is a constructive proof of the reuse potential in systems
that support "generic types", GC and first-class functions (e.g. procedures
in records, etc.)  As many whining system managers will tell you, Lisp
systems are big.  That bigness is mainly because a Lisp image has lots of
code in it; Lisp programs tend to have big working sets because lots of
that code is used.  

Coming from a Lispy language perspective, the main challenge is not to make
the system smaller, but to make it bigger so that there is more stuff out
there that the programmer can use.  (Of course, we want to maintain similar
cost-effectiveness, rather than just bloating with junk.)

>PS: Writers of collection modules in GC-based environments should not
>forget to create dynamically-expanding versions of their collections. 
>Itis very annoying to have to estimate the size of collections in
>advance, things always blow up on large data sets.

Yep, this is often something that we have to flame new Lisp programmers for
when we are breaking them in.  Of course, if you use a linked-list
implementation of your data structures, this happens for free.

  Rob

hopper@ntmtv.UUCP (Ian Hopper) (09/20/89)

From article <11701@boulder.Colorado.EDU>, by scotth@boulder.Colorado.EDU (Scott Henninger):
> |>From: hopper@ntmtv.UUCP (Ian Hopper)
> |
> |I have always felt that some form of Garbage Collection is
> |needed in order to do a decent job on reusable "Collection"
> |modules.  Since the current favorite language (C++) does
> |not consistiently (or easily) support GC, we do not see
> |good quality collection modules.
> 
> Quality in what sense? Program efficiency? Cognitive efficiency (i.e. how
> readable it is)? Correctness? Reliability?
> 
> -- Scott
>    scotth@boulder.colorado.edu

That is a perfectly reasonably question, given my vague posting.
Sorry to waste your time on the first pass. (Novice poster.)
All of your suggesions apply, I would say.  Performance can be an
application specific issue, so is GC.

I interpret "quality" in a reusable package to mean: lack of internal 
bugs and an interface that allows the package to be used without hassles.
Typical hassles are listed as items 2-5 below.

The (unstated) question I am getting at is: do we need to assume 
mark-and-sweep-like garbage collection in order to write siginificant 
amounts of reusable software?

One disclaimer: I don't have a copy of the Gorlan "OOPS" C++ library,
so I am forced to speculate on what is available from it.  I did not
wish to imply that it (or any other particular library) is broken or
"bad", rather that such "good" implementations are difficult, and there
are very few of them around.  Only OOPS is in a language without a 
standard garbage collector.  The others have GC's: Smalltalk and Eiffel.
Eiffel has a GC, but the classes suffer from the fixed-at-creation
problem my "PS" was referring to.  Smalltalk may not have the 
performance that some applications need and lacks static type checking.

I believe that one of the following apply to a reusable collection "mocule":

	1) There is a mark-and-sweep garbage collector available.

	I claim this is "best", provided you can afford GC.  I know
	if several GC's that ease the "hiccups" that the classic M-S
	approach required.

	2) The library implements a mark-sweep garbage collector.
	   Perhaps restricting the gc capability to objects that
	   comply with some restrictions.

	This is OK, but there are restrictions on use.  M-S garbage
	collectors are often not portable.

	3) The library uses some form of reference counting and punts the
	   problem of circular references to the client of the library.

	If circular references are provably not a problem for the
	particular case, then this is perfect.  Again, there may
	be additional restrictions on what sorts of objects can be
	put into a collection. (SubClass of: ReferenceCountableObject.)

	4) The library copies collection elements into and out of the
	   collection objects.
	
	This is slow for contents that are large objects in their own right.
	Putting an object into and then retrieving that object creates
	a copy, rather than the original object.  This may be inappropriate.
	Objects cannot tell whether they are a member of a collection,
	except by value.  Membership in multiple collections is not
	easily represented, except by value.

	5) The collection class forces it's users to carefully track
	   the "ownership" of objects.  This makes it difficult to
	   allow an object to be a member of a varying number of 
	   collections without extra book-keeping.

	The source of many subtle bugs in user's code.  I believe that
	this is the "typical" approach.

(Still :) Interested in responses,

	Ian