comp.lang.ada
 help / color / mirror / Atom feed
From: adam@irvine.com
Subject: How to Use Abstract Data Types
Date: 1998/04/22
Date: 1998-04-22T00:00:00+00:00	[thread overview]
Message-ID: <6hm556$95u$1@nnrp1.dejanews.com> (raw)


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.

One of the functions I would want is one to search for all books whose
title matches a certain regular expression.  My usual idiom for this
sort of scan is to declare four subprograms---something like
Start_Scan (which gets things started but doesn't return any items),
More_Items (which returns TRUE if there are more items to return),
Next_Item (which returns the next one), and Close_Scan (to clean up).
This idiom also involves declaring a type to hold "current item"
information needed by the scan routines; an object of this type is set
up by Start_Scan, More_Items tests the object, and Next_Item modifies
it.  I strongly prefer this over having the current scan information
"hidden" globally inside the package body, since it means there's no
problem for two parts of the calling program to conduct two scans in
parallel.

If I define a record to hold the current scan information, it would
also have to be abstract (right?), since its contents would vary
depending on the implementation.  That is, for libraries implemented
as a tree file, it might contain a stack of node addresses, or
something like that.

So say my package spec looks 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;

        ... procedure(s) to set up a new Library object

        procedure Scan_By_Title (Lib            : in Library;
                                 Reg_Expression : in String;
                                 Scan           : out Scan_Info;
                                 RE_Error       : out Boolean);
        function More_Books (Scan : Scan_Info) return Boolean;
        procedure Next_Book (Scan     : in out Scan_Info;
                             Bk       : out Book);
        procedure Close_Scan (Scan : in out Scan_Info);

        ... etc.

    end Library_Package;

For Scan_By_Title, RE_Error would be set to TRUE if Reg_Expression is
ill-formed.

But it looks like this isn't going to work.  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.

Am I missing something trivial here?

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.

                                -- thanks, Adam

-----== Posted via Deja News, The Leader in Internet Discussion ==-----
http://www.dejanews.com/   Now offering spam-free web-based newsreading




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

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
1998-04-22  0:00 adam [this message]
1998-04-23  0:00 ` How to Use Abstract Data Types Jacob Sparre Andersen
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