comp.lang.ada
 help / color / mirror / Atom feed
From: sparre@meyer.fys.ku.dk (Jacob Sparre Andersen)
Subject: Re: How to Use Abstract Data Types
Date: 1998/04/23
Date: 1998-04-23T00:00:00+00:00	[thread overview]
Message-ID: <6hnea1$6qv$1@balder.adm.ku.dk> (raw)
In-Reply-To: 6hm556$95u$1@nnrp1.dejanews.com

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 10657 bytes --]


------------------------------------------------------------------------------
--  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               --
----------------------------------------------------------------------------




  reply	other threads:[~1998-04-23  0:00 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1998-04-22  0:00 How to Use Abstract Data Types adam
1998-04-23  0:00 ` Jacob Sparre Andersen [this message]
1998-04-30  0:00 ` Robert I. Eachus
     [not found]   ` <matthew_heaney-ya023680003004981709380001@news.ni.net>
1998-05-05  0:00     ` Stephen Leake
1998-05-05  0:00       ` Matthew Heaney
1998-05-06  0:00         ` Stephen Leake
  -- strict thread matches above, loose matches on Subject: below --
1998-04-30  0:00 adam
1998-05-06  0:00 ` Robert I. Eachus
1998-05-04  0:00 adam
1998-05-06  0:00 ` Robert I. Eachus
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox