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.1 required=5.0 tests=BAYES_00, PP_MIME_FAKE_ASCII_TEXT,T_FILL_THIS_FORM_SHORT autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII X-Google-Thread: 103376,6b85f5fd782a1527 X-Google-Attributes: gid103376,public From: sparre@meyer.fys.ku.dk (Jacob Sparre Andersen) Subject: Re: How to Use Abstract Data Types Date: 1998/04/23 Message-ID: <6hnea1$6qv$1@balder.adm.ku.dk> X-Deja-AN: 346962540 References: <6hm556$95u$1@nnrp1.dejanews.com> Organization: University of Copenhagen Newsgroups: comp.lang.ada Date: 1998-04-23T00:00:00+00:00 List-Id: ------------------------------------------------------------------------------ -- Jacob: -- -- This message should be ready to compile. -- -- My reply is directed only to the problem Adam presented. There are no -- general guidelines here (that I am aware of). -- -- I know that my choice of coding style can be (and has been) discussed, -- but lets keep it separate from the library/OO ADT business. ------------------------------------------------------------------------------ -- Adam (adam@irvine.com): -- -- I'm just starting to use some of the advanced OO features of Ada 95, -- and I've run into a situation that I don't know what the best solution -- is. Or maybe I'm completely confused about something. -- -- Here's an example of what I'm trying to accomplish. I'd like to -- define an abstract data type, Library, that denotes a collection of -- books. Since this collection could be implemented in several -- ways---say, as a flat file, or a file organized as a tree, or perhaps -- not a file at all but rather by querying some other site on the -- Internet---the type would be an abstract tagged type, and the package -- that declares it would declare abstract procedures to deal with it. -- I'd assume that the type Book, which represents one book, would be an -- abstract type, also. ------------------------------------------------------------------------------ -- Jacob: -- -- Here is how I see the problem at hand: -- -- You have books of various kinds. The common features of all kinds -- of all kinds of books are collected in type Abstract_Book.Object. -- -- A library is a collection of books. You can walk through a library -- looking for a book, add books to a library, remove books from a library -- (even though you shouldn't), read books in a library, and you can -- borrow books from and return them to a library. -- -- Some libraries even have indexes to the library so you can look up -- books by their title, author, or subject. ------------------------------------------------------------------------------ -- Abstract book: with Libraries; with String_Lists; package Abstract_Book is type Object is abstract tagged private; subtype Class is Object'Class; type Reference is access all Class; function Title (Book : in Abstract_Book.Object) return String is abstract; function Authors (Book : in Abstract_Book.Object) return String_Lists.List is abstract; function Subject (Book : in Abstract_Book.Object) return Libraries.Subject_Code is abstract; private -- I have chosen to keep the base information about the books out of -- Abstract_Book.Object in case we are going to work with "books" where -- the information can be found through some other means. type Object is abstract tagged null record; end Abstract_Book; ------------------------------------------------------------------------------ -- Abstract library: with Abstract_Book; with Libraries; package Abstract_Library is type Object is abstract tagged private; subtype Class is Object'Class; type Reference is access all Class; Full : exception; Not_Found : exception; procedure Add (To : in out Abstract_Library.Object; Book : in Abstract_Book.Class; ID : out Libraries.Book_ID) is abstract; procedure Remove (From : in out Abstract_Library.Object; ID : in Libraries.Book_ID; Book : out Abstract_Book.Class) is abstract; procedure Remove (From : in out Abstract_Library.Object; Book : in Libraries.Book_ID) is abstract; procedure Read_Book (Library : in Abstract_Library.Object; ID : in Libraries.Book_ID; Book : out Abstract_Book.Class) is abstract; procedure Borrow (From : in out Abstract_Library.Object; ID : in Libraries.Book_ID; Book : out Abstract_Book.Class) is abstract; procedure Return_Book (Library : in out Abstract_Library.Object; Book : in Abstract_Book.Class) is abstract; type Look_At_Reference is access procedure (Book : in Abstract_Book.Class; ID : in Libraries.Book_ID; Stop : out Boolean); procedure Walk_Through (Library : in Abstract_Library.Object; Look_At : in Look_At_Reference; Terminated : out Boolean); type Process_Reference is access procedure (Book : in out Abstract_Book.Class; Stop : out Boolean); procedure Walk_Through (Library : in Abstract_Library.Object; Process : in Process_Reference; Terminated : out Boolean); private type Object is abstract tagged null record; end Abstract_Library; ------------------------------------------------------------------------------ -- Abstract book query: with Libraries; package Abstract_Book_Query is type Object is abstract tagged private; subtype Class is Object'Class; type Reference is access all Class; -- The initial state of a query should always be before the first result -- from the query. -- -- Current will fail if called before Next has been called. procedure Current (Query : in Abstract_Book_Query.Object; Book : out Libraries.Book_ID) is abstract; procedure Next (Query : in out Abstract_Book_Query.Object; Book : out Libraries.Book_ID) is abstract; function End_Of_Query (Query : in Abstract_Book_Query.Object) return Boolean is abstract; private type Object is abstract tagged null record; end Abstract_Book_Query; ------------------------------------------------------------------------------ -- Abstract indexed library: with Abstract_Book_Query; with Abstract_Library; with Libraries; with Pattern_Matching; package Abstract_Indexed_Library is type Object is abstract new Abstract_Library.Object with private; subtype Class is Object'Class; type Reference is access all Class; -- Here I declare *abstract* constructors for some book queries. -- You will have to declare a non-abstract descendant of -- Abstract_Book_Query.Object to implement the constructors. function Search_For_Title (Library : in Abstract_Indexed_Library.Object; Pattern : in Pattern_Matching.Pattern) return Abstract_Book_Query.Class is abstract; function Search_For_Author (Library : in Abstract_Indexed_Library.Object; Pattern : in Pattern_Matching.Pattern) return Abstract_Book_Query.Class is abstract; function Search_For_Subject (Library : in Abstract_Indexed_Library.Object; Subject : in Libraries.Subject_Code) return Abstract_Book_Query.Class is abstract; private type Object is abstract new Abstract_Library.Object with null record; end Abstract_Indexed_Library; ------------------------------------------------------------------------------ -- Adam: -- -- One of the functions I would want is one to search for all books whose -- title matches a certain regular expression. -- -- [cut] -- -- If I were to write a procedure that lists all the books in a library whose -- titles match, I'd want to be able to write: procedure List_Books_With_Matching_Titles (Lib : in Library'Class; Title_Pattern : in String) is -- declarations begin Scan_By_Title (Lib, Title_Pattern, List_Scan, Error); if Error then Insult_The_User; return; end if; while More_Books (List_Scan) loop Next_Book (List_Scan, The_Book_To_List); List_Book (The_Book_To_List); end loop; Close_Scan (List_Scan); end List_Books_With_Matching_Titles; -- But I don't see how this can be done, since I can't declare List_Scan. -- I can't declare it as Library_Package.Scan_Info since that is an -- abstract type, and I can't declare it as Library_Package.Scan_Info'Class -- since I need an initializer. I guess I could declare it as -- Scan_Info'Class if I turned Scan_By_Title into a function, but then I'd -- have to find some other way to take care of the RE_Error output (in this -- particular case, I could use an exception, but imagine a case where I want -- to return something that isn't a simple success/failure boolean). I also -- don't see how to declare The_Book_To_List, and I can't see turning -- Next_Book into a function since Scan has to be an "in out" parameter. ------------------------------------------------------------------------------ -- Jacob: -- -- I rewrite your procedure List_Books_With_Matching_Titles with some minor -- changes: with Abstract_Book_Query; with Abstract_Indexed_Library; with Libraries; with Pattern_Matching; procedure List_Books (Library : in Abstract_Indexed_Library.Class; Title : in Pattern_Matching.Pattern) is use Abstract_Book_Query; use Abstract_Indexed_Library; Query : Abstract_Book_Query.Reference; Book : Libraries.Book_ID; begin Query := new Abstract_Book_Query.Class' (Search_For_Title (Library => Library, Pattern => Title)); while not End_Of_Query (Query.all) loop Next (Query => Query.all, Book => Book); --List_Book (Book); end loop; end List_Books; ------------------------------------------------------------------------------ -- Various stuff to get things to compile: package Libraries is type Subject_Code is new String (1 .. 6); subtype Book_ID is Natural; end Libraries; package Pattern_Matching is type Pattern is new String; end Pattern_Matching; package String_Lists is type List is new String; end String_Lists; -- Greetings, -- -- Jacob -- ---------------------------------------------------------------------------- -- Jacob Sparre Andersen -- E-mail: Jacob.Sparre.Andersen@risoe.dk -- -- National Laboratory Ris� -- Phone.: (+45) 46 77 51 23 -- -- Systems Analysis -- Fax...: (+45) 46 77 51 99 -- ----------------------------------------------------------------------------