From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,8a4c4f5d7ace34fb,start X-Google-Attributes: gid103376,public From: adam@irvine.com Subject: Subject: Active Iteration (was: How to use abstract data types) Date: 1998/05/06 Message-ID: <6iq9cl$i3t$1@nnrp1.dejanews.com> X-Deja-AN: 350829221 X-Http-User-Agent: Mozilla/3.0 (X11; I; Linux 2.0.18 i586) Organization: Deja News - The Leader in Internet Discussion X-Article-Creation-Date: Wed May 06 18:15:50 1998 GMT Newsgroups: comp.lang.ada Date: 1998-05-06T00:00:00+00:00 List-Id: Matthew Heaney wrote: > Here's the idea I had for the library iterator. The Library_Package.Test > package exports an active iterator that I was hoping to use to iterate over > a Test_Library. > > However, I can't get this code to compile! My compiler is telling me the > generic actual types don't match the formal discriminant types. > > If your compiler can compile this, let me know and I'll report a bug to > ACT. If this is simply an illegal Ada program, then maybe someone can > figure out an alternative solution. > > The idea was to make the List_Books operation a generic procedure that > imports an iterator type as a generic formal type, to iterate over the > library object passed in. I do it this way because importing an iterator > as derived from an abstract root iterator type won't work, because formal > derived types cannot have a known discriminant (see RM95 12.5.1 (11), a > bummer of a paragraph). So I just import everything as a non-tagged type > (even though the actual type may in fact be tagged), and import the ops > formal subprogram parameters ("implementation inheritance"). > > But I can't get the instantiation of List_Books to compile. Maybe you'll > have more luck. I haven't yet taken the time to figure out what's wrong yet. But I plan to, because I'm sure that I'd learn a lot about Ada 95 details by doing so. Anyway, it kind of surprises me that the solution involves a generic that takes subprogram parameters. The reason it surprises me is this: based on what I thought OO was "supposed" to be, I expected that the routines in Library_Package, including the ones that step through the iterator, would be dispatching routines. That is, at some point the code would have to select which routine to call, i.e. perform an indirect subroutine call; I expected this to take place through the dispatching mechanism, rather than through a generic formal subprogram (the Ada 83 way?). Having to use a generic to handle something I thought polymorphism should be able to handle is a bit disappointing to me. I tried another method for solving the problem. Since my original problem had to do with the fact that I couldn't use an abstract type as an "out" parameter, I tried making it a pointer. The program listed below compiles and runs perfectly, and it uses the dispatching mechanism for selecting the iteration routines, like it "should". The drawbacks I can see with this approach are: (1) it forces you to use the allocation mechanism, bringing up all the problems with garbage collection, dangling references, etc. (*); (2) the parameters of type Library now have to be "access" to avoid accessibility problems; and unfortunately, this requirement propagates, so that if I wrote another subprogram S to take a Library parameter and call List_Books on that library, S would have to declare the Library to be an "access" parameter also. This, to me, is a flaw. (I could perhaps avoid this by making the private part of Test_Library be a pointer to some internal data, and then making the private part of Test_Iterator_Object contain a copy of this pointer instead of an access to the whole Test_Library. Another possibility would be to make the Library a parameter to all the other iteration routines.) I'm not particularly happy with either solution. (*) Note: Personally, this isn't a serious drawback for me; but my perception is that some programmers have reasons for trying to avoid the allocation mechanism. -- Adam =============================================================================== package Library_Package is type Library is abstract tagged null record; type Book is abstract tagged null record; type Iterator_Object is abstract tagged null record; type Iterator is access all Iterator_Object'class; function The_Library return Library is abstract; function Title (Bk : Book) return string is abstract; procedure Scan_For_Substring (Lib : access Library; Iter : out Iterator; Substr : in string) is abstract; function Is_Done (Iter : access Iterator_Object) return Boolean is abstract; function Get_Book (Iter : access Iterator_Object) return Book'class is abstract; procedure Advance (Iter : access Iterator_Object) is abstract; end Library_Package; with Library_Package; package Test_Library_Package is type Test_Library is new Library_Package.Library with private; type Test_Book is new Library_Package.Book with private; type Test_Iterator_Object is new Library_Package.Iterator_Object with private; function The_Library return Test_Library; function Title (Bk : Test_Book) return string; procedure Scan_For_Substring (Lib : access Test_Library; Iter : out Library_Package.Iterator; Substr : in string); function Is_Done (Iter : access Test_Iterator_Object) return Boolean; function Get_Book (Iter : access Test_Iterator_Object) return Library_Package.Book'class; procedure Advance (Iter : access Test_Iterator_Object); private type String_P is access string; type Book_Info is record Title : String_P; end record; type Book_Array is array (Natural range <>) of Book_Info; type Test_Library is new Library_Package.Library with null record; type Test_Library_Acc is access all Test_Library; type Test_Book is new Library_Package.Book with record Info : Book_Info; end record; type Test_Iterator_Object is new Library_Package.Iterator_Object with record Lib : Test_Library_Acc; Search_String : String_P; Index : Natural; end record; end Test_Library_Package; with Ada.Strings.Fixed; package body Test_Library_Package is My_Library : constant Book_Array := ( (Title => new string' ("A Time To Kill")), (Title => new string' ("The Firm")), (Title => new string' ("The Pelican Brief")), (Title => new string' ("The Client")), (Title => new string' ("The Rainmaker")), (Title => new string' ("The Runaway Jury")) ); function The_Library return Test_Library is begin return (null record); end The_Library; function Title (Bk : Test_Book) return string is begin return Bk.Info.Title.all; end Title; procedure Search (Iter : in out Test_Iterator_Object) is begin while Iter.Index <= My_Library'last loop exit when Ada.Strings.Fixed.Index (My_Library (Iter.Index).Title.all, Iter.Search_String.all) /= 0; Iter.Index := Iter.Index + 1; end loop; end Search; procedure Scan_For_Substring (Lib : access Test_Library; Iter : out Library_Package.Iterator; Substr : in string) is Iter_Obj : Test_Iterator_Object; begin Iter_Obj.Lib := Lib; -- the .Lib isn't actually used for anything in this -- package body, but in real life the routines below would -- use it Iter_Obj.Search_String := new string' (Substr); Iter_Obj.Index := My_Library'first; Search (Iter_Obj); Iter := new Test_Iterator_Object' (Iter_Obj); end Scan_For_Substring; function Is_Done (Iter : access Test_Iterator_Object) return Boolean is begin return (Iter.Index > My_Library'last); end Is_Done; function Get_Book (Iter : access Test_Iterator_Object) return Library_Package.Book'class is begin return Test_Book' (Info => My_Library (Iter.Index)); end Get_Book; procedure Advance (Iter : access Test_Iterator_Object) is begin Iter.Index := Iter.Index + 1; Search (Iter.all); end Advance; end Test_Library_Package; with Library_Package; package List_Package is procedure List_Books (Lib : access Library_Package.Library'class; Substr : in string); end List_Package; with Text_IO; package body List_Package is procedure List_Books (Lib : access Library_Package.Library'class; Substr : in string) is Iter : Library_Package.Iterator; begin Library_Package.Scan_For_Substring (Lib, Iter, Substr); while not Library_Package.Is_Done (Iter) loop declare Bk : Library_Package.Book'class := Library_Package.Get_Book (Iter); begin Text_IO.Put_Line (Library_Package.Title (Bk)); end; Library_Package.Advance (Iter); end loop; end List_Books; end List_Package; with Test_Library_Package; with List_Package; procedure Libtest3 is The_Lib : aliased Test_Library_Package.Test_Library; begin The_Lib := Test_Library_Package.The_Library; List_Package.List_Books (The_Lib'access, "m"); end Libtest3; -----== Posted via Deja News, The Leader in Internet Discussion ==----- http://www.dejanews.com/ Now offering spam-free web-based newsreading