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