Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!mailrus!wuarchive!gem.mps.ohio-state.edu!ginosko!uunet!mcsun!ukc!cam-cl!scc
From: scc@cl.cam.ac.uk (Stephen Crawley)
Newsgroups: comp.sw.components
Subject: Re: List ADT example
Message-ID: <915@scaup.cl.cam.ac.uk>
Date: 25 Sep 89 16:44:36 GMT
References: <902@scaup.cl.cam.ac.uk> <6555@hubcap.clemson.edu>
Sender: news@cl.cam.ac.uk
Organization: U of Cambridge Comp Lab, UK
Lines: 94

Bill Wolfe writes:
>
>  When you make your instantiation of the list type for objects of
>  type A, you must fulfill the instantiation requirements.  This will
>  normally include supplying assignment and destruction procedures for 
>  objects of type A.  If you send an object into the list, the assignment
>  procedure will be used to create a resident copy.  If you direct the
>  removal of an object from the list, the destruction procedure will be
>  used to destroy it.  (See Booch, "Software Components with Ada")
>

First objection: I don't want to put a copy of the instance of A into the list
twice.  I want to put the SAME instance of A into the list twice.  If
A is a mutable type (i.e. has operations that can change a value) this
is a significant semantic difference.  

Actually, though you SAY "make a resident copy [of the object]" I think 
you MEAN something slightly different; "make a resident copy of the ref
to the object".  Unfortunately, Ada makes a distinction between pointers
and non-pointers and this makes such things hard to describe concisely.  
I'll assume you meant this, and also that the object has an internal 
reference count that is incremented by the ADT's "assign" and decremented 
by its "destroy".  (The ref count is essential if an object is to be appear 
more than once in a list)

Second objection: You do not say how the assign and destruct operations 
get invoked when an instance of A returned by the LIST ADT to the 
application.  In general this requires some cooperatation on the part
of the application.  

In ADA it seems that by declaring A in the ADT as a "limited private" type 
the ADT can force the application to cooperate as far as assignment is
concerned.  (Since limited private types do not support ANY operations except
for those declare by the PACKAGE, the application programmer can be forced 
to apply the ASSIGN or DESTRUCT operation to the result of every A operation 
that returns an A instance in order to get his program to type check.)

However, I can't see how the application is forced to call DESTROY on an A
variable when its declaration scope exits.  [Please correct me if I am wrong 
.. I am NOT an ADA expert.]

If this is the case, then it is a trivial matter to generate an example
where correct storage management depends on the application programmer 
not making a mistake.  In other words, this is not a correct solution.

---

The ADA partial solution to storage management for lists strikes me as 
ugly.  For every ADT A, the corresponding PACKAGE needs to declare two 
types and a bunch of extra operators (ASSIGN, DESTROY and others that
are forced on us by exporting the type of A as a LIMITED PRIVATE)  Finally, 
since := can't be overloaded, the programmer has to use an awkward idiom
to assign an A instance to a variable. 

Then there is the issue of efficiency.  [After all, efficiency IS the 
reason we are not using GC'ed storage...]  Every time an instance of
the ADT A is assigned, we execute the ASSIGN operator which would be
coded something like

TYPE
  A_obj = RECORD [
    ref_count:	int,
    ...
    ]
	
  A = POINTER TO A_obj


-- Assign: updates the A variable given by 'dest'
-- to hold the A object given by 'source'
assign = PROCEDURE (source: IN A, dest: IN OUT A)
  IF dest ~= 'uninitialised' THEN
    -- If there is already a A value in 'dest', decrement its ref count.
    dest^.ref_count := dest^.ref_count - 1
    IF dest^.ref_count = 0 THEN
      -- deallocate dest^ and all of its fields.
      END
    END
  source^.ref_count := source^.ref_count + 1 
  dest := source
  END assign
  

That is a LOT of work for a simple assignment!

Contrast it with the GC'ed case where assignment is probably 1 machine
instruction unless you are using some useless reference counting garbage 
collection scheme.

If the ratio of list access to list building operations is large enough 
(I'd guess maybe 10 to 1 if ASSIGN isn't expanded inline), it will be 
MORE EFFICIENT TO USE GARBAGE COLLECTION.

-- Steve