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,6b85f5fd782a1527 X-Google-Attributes: gid103376,public From: adam@irvine.com Subject: Re: How to Use Abstract Data Types Date: 1998/04/30 Message-ID: <6ib2o9$4gq$1@nnrp1.dejanews.com> X-Deja-AN: 349252489 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: Thu Apr 30 23:50:32 1998 GMT Newsgroups: comp.lang.ada Date: 1998-04-30T00:00:00+00:00 List-Id: Robert Eachus wrote: > > Am I missing something trivial here? > > -- Yes, but you can be forgiven because it is not trivial in many OO > -- langauges. There are cases where you have to use access parameters > -- and all that to duplicate the normal way of doing iterators in > -- other languages. In Ada, you are always better off making > -- iterators objects, but in Ada 95 the much cleaner way of doing > -- iterators is to use instances of generic packages as the iterator > -- objects. Sounds compilicated, but it isn't. First, we will > -- realize that Books and libraries are separate abstractions: > > package Books is > > type Book is ...; > function Title(B: Book) return String; > ... > end Books; > > with Books > package Libraries is > > type Library is abstract tagged null record; > > -- various abstract operations on Libraries. > > generic > type Some_Library is new Library with private; > This_Library: in out Some_Library; > package Iterator is > function More return Boolean; > function Next return Book'Class; > end Iterator; > > private > ... > end Libraries; > > > The body of Iterator will call (abstract) primitives on Libraries. > Of course, when Iterator is instantiated, it will be on a non-abstract > class, so there will be actual code to call. But that is not your > worry. But I'm not sure this is what I want. Unless there's something else I'm missing, having an Iterator generic package whose body calls abstract primitives on Libraries isn't what I want. Let me try to go into more detail. My original package spec looked something like this: package Library_Package is type Library is abstract tagged null record; type Book is abstract tagged null record; type Scan_Info is abstract tagged null record; -- (my iterator) procedure Scan_By_Title ... is abstract; function More_Books ... is abstract; procedure Next_Book ... is abstract; procedure Close_Scan ... is abstract; end Library_Package; What I envisioned here is that different packages could deal with different implementations of the library. For example, I could perhaps define something like package Amazon_Library_Package is type Library is new Library_Package.Library with private; type Book is new Library_Package.Book with private; etc. end Amazon_Library_Package; where the purpose of this package is to define a "library" as all the books in amazon.com. The code for Scan_By_Title, More_Books, Next_Book, as well as the private parts of the types I've defined, would be set up specifically to FTP to amazon.com and send it commands that cause amazon.com to return the information needed to implement these functions. (Note: I'm just pretending that amazon.com would support this kind of thing.) Similarly, another package, B_Tree_Library_Package, might allow the program to use a file as a library, where all the entries in the library are organized as a B-tree, and so on. So given that Scan_By_Title, More_Books, and Next_Book would have to be coded specially for each implementation of Library_Package, I don't see how setting up a generic iterator the way you've done it solves the problem. Also, when you say that the body of Iterator calls abstract primitives on Libraries, I don't see how those primitives would be written. It seems like the abstract primitives I'd have to define in Libraries would be, essentially, the same Scan_By_Title, More_Books, Next_Book, etc. routines I already tried to define, and those would have the same problem with OUT parameters that I already complained about. So it seems like all you've done is pushed the problem one level back. I'll grant that you could implement these primitives (perhaps in the private part of Libraries) using a "dirty" method that uses accesses to the abstract types as OUT parameters, and provide Iterator as a "clean" interface to the outside world to avoid the dirty stuff. Is this what you were getting at with your response? (Personally, though, I don't see much benefit from adding this extra layer.) > > What is the cleanest way to accomplish what I'm trying to do? This > > looks like such a typical use of polymorphism that I'd be surprised if > > there were no intuitive way to do it. > > Now to write your Scan_by_Title, lets make it a child of Libraries: > > generic > type Some_Library is new Library with private; > procedure Libraries.Scan_By_Title (Lib : in Some_Library; > Reg_Expression : in String; > Scan : out Scan_Info; > RE_Error : out Boolean); > > procedure Libraries.Scan_By_Title (Lib : in Some_Library; > Reg_Expression : in String; > Scan : out Scan_Info; > RE_Error : out Boolean) is > ... > package Local_Iterator is new Libraries.Iterator(Some_Library, Lib); > begin > ... > while Local_Iterator.More loop > Process_Book(Local_Iterator.Next, {other parameters}); > end loop; > end Libraries.Scan_By_Title; > > I made this a child of Libraries for exposition purposes, you may > want to have Scan_By_Title as an abstract primitive of the Library > type and in effect, require that all non-abstract types derived from > Library provide a body, or you could make it a non-abstract primitive. > My leaning is to provide the Iterator as a child of Libraries, but to > provide the search function as an abstract primitive. In other words, > some Library implementations may not have a concept of an ordering > among books, but might still provide a search mechanism. Unfortunately, you've reduced some flexibility by doing this, because there's no guarantee that Process_Book (whatever it is---you haven't defined it---is it a generic subprogram parameter?) is going to be easy to write. I often define iterators as four routines (initialize, test-for-more, get-next, close) instead of, say, writing a generic "do-this-for-all-the-books" routine (or a "do-for-all" routine that takes an access-to-subprogram parameter), precisely to give myself this flexibility. For example, I might want to stop the iterator after 10 books, because I only have room on the screen to display 10, and I want to wait for the user to input a "go to next page" command before bothering to retrieve the next 10. This would be especially necessary when FTP'ing from amazon.com; you don't want to have to query for the entire set of matches until you know you'll need them. Or, maybe I want to display three books on each line: begin Scan_By_Title (Lib, Title_Pattern, List_Scan, Error); if Error then ... end if; while More_Books (List_Scan) loop Next_Book (List_Scan, Book); Title1 := new String' (Title (Book)); if not More_Books (List_Scan) then Title2 := null; else Next_Book (List_Scan, Book); Title2 := new String' (Title (Book)); end if; if not More_Books (List_Scan) then Title3 := null; else Next_Book (List_Scan, Book); Title3 := new String' (Title (Book)); end if; Text_IO.Put_Line (Make_One_Line_Out_Of_Three_Titles (Title1, Title2, Title3)); end loop; Close_Scan (List_Scan); end List_Books_With_Matching_Titles; My point here is that there may well be cases where a simple "execute-the-same-code-for-every-item-iterated" approach isn't the best, and I don't see a reason why I would want to be locked into that approach, the way your Scan_By_Title routine seems to. (The above example would actually be pretty easy to fit into the Process_Book approach, but that's not relevant.) ============================= I'll look at my real-life code to see if it would benefit from coding an iterator as you suggest. For now, though, I've worked around my problem by using access types for the OUT parameters. -- Adam -----== Posted via Deja News, The Leader in Internet Discussion ==----- http://www.dejanews.com/ Now offering spam-free web-based newsreading