comp.lang.ada
 help / color / mirror / Atom feed
* Help with a Remote Type / Iterator
@ 2003-12-01  3:48 Michael Lamarre
  2003-12-01  5:31 ` Robert I. Eachus
  2003-12-01 23:00 ` Nick Roberts
  0 siblings, 2 replies; 6+ messages in thread
From: Michael Lamarre @ 2003-12-01  3:48 UTC (permalink / raw)


Hi there. This is my first post here, so please be gentle. I'm 
developing a distributed Ada program at work. I have a very skilled 
mentor helping me, but we're having a hell of a time with one particular 
problem. I've included simple mock-ups of the packages/types involved 
below, but let me give a high-level explanation first.

I have a record type I've defined in package A. In package A.CHILD, I 
want to define a type that is a collection of these records. For 
stylistic reasons, we'd rather declare all of the types in the spec and 
not have any incomplete type declarations in the spec. Both A and 
A.CHILD are REMOTE_TYPES (RT) packages.

What we need is some kind of iterator for the collection type declared 
in A.CHILD. We've tried a passive iterator, but some of the stuff we 
need to do while iterating just won't work given that the passive 
iterator needs to take an access-to-subprogram parameter, which, in a RT 
package must be a remote subprogram. We need the flexibility of an 
active iterator.

Naturally, the standard way to do this is to have an iterator type that 
takes an access discriminant that points at the collection the iterator 
is associated with. However, this won't work, as the compiler informs us 
that a non-remote-access type must have user-defined READ and WRITE 
attributes. As an access discriminant is an anonymous type, this is 
impossible. I tried using a named access type as the discriminant, but 
the code in the body for the iterator subprograms wouldn't compile, 
saying something like "invalid dereference of a remote access to 
classwide type".

Anyway, here's my sample code, simplified to drastic degrees. Can anyone 
help me figure out how to come up with an iterator for my 
COLLECTION_TYPE? Is there a standard way to iterate over a remote type? 
Thanks in advance.

-- Mike L.

---[ File: a.ads ]-------------------

package A is

    pragma REMOTE_TYPES(A);

    type RECORD_TYPE is tagged limited private;

    type RECORD_PTR_TYPE is access all RECORD_TYPE'CLASS;

    -- various operations on RECORD_TYPEs.

private

    type RECORD_TYPE is tagged limited record
       -- Various record fields.
    end record;

end A;

---[ File: a-child.ads ]-------------

package A.CHILD

    pragma REMOTE_TYPES(CHILD);

    type COLLECTION_TYPE(CAPACITY : NATURAL) is tagged limited private;

    type COLLECTION_PTR_TYPE is access all COLLECTION_TYPE'CLASS;

    -- Various operations on COLLECTION_TYPEs.

private

    type REC_ARRAY_TYPE is array (NATURAL range <>) of RECORD_PTR_TYPE;

    type COLLECTION_TYPE(CAPACITY : NATURAL) is tagged limited record
       RECORD_ARRAY : REC_ARRAY_TYPE(1..CAPACITY);
       -- Various other fields.
    end record;

end A.CHILD;




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with a Remote Type / Iterator
  2003-12-01  3:48 Help with a Remote Type / Iterator Michael Lamarre
@ 2003-12-01  5:31 ` Robert I. Eachus
  2003-12-01 13:37   ` Michael Lamarre
  2003-12-01 23:00 ` Nick Roberts
  1 sibling, 1 reply; 6+ messages in thread
From: Robert I. Eachus @ 2003-12-01  5:31 UTC (permalink / raw)


Michael Lamarre wrote:

> I have a record type I've defined in package A. In package A.CHILD, I 
> want to define a type that is a collection of these records. For 
> stylistic reasons, we'd rather declare all of the types in the spec and 
> not have any incomplete type declarations in the spec. Both A and 
> A.CHILD are REMOTE_TYPES (RT) packages.
> 
> What we need is some kind of iterator for the collection type declared 
> in A.CHILD. We've tried a passive iterator, but some of the stuff we 
> need to do while iterating just won't work given that the passive 
> iterator needs to take an access-to-subprogram parameter, which, in a RT 
> package must be a remote subprogram. We need the flexibility of an 
> active iterator.

This is not necessarily a solution, just trying to understand what you 
are doing....

Do you really require that your iterator run on processor A, accessing 
objects from processor B?  If so it can be done.  But as you sort of 
point out, the problem is that you are trying to cram everything into 
one package.

If you really need the data transfered from processor to processor, you 
will need to provide 'Read and 'Write.  These can be defined in terms of 
the subcomponents for the actual type, see the Rationale, I think for 
details.

But I really suspect that you are confusing (in the other meaning of 
confusing--mixing them together) two different things, a type which is a 
remote type, and a local iterator over collections of objects of the 
type.  If the collections are distributed, you have a big design job 
just defining what iteration means.  (Do you want to iterate over a 
snapshot of the container state, iterate over all the objects in a 
particular partition, then do the next partition, iterate over all 
partitions in parallel, or is there other implicit order of iteration, etc.)

-- 
                                           Robert I. Eachus

100% Ada, no bugs--the only way to create software.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with a Remote Type / Iterator
  2003-12-01  5:31 ` Robert I. Eachus
@ 2003-12-01 13:37   ` Michael Lamarre
  2003-12-02 23:17     ` Robert I. Eachus
  0 siblings, 1 reply; 6+ messages in thread
From: Michael Lamarre @ 2003-12-01 13:37 UTC (permalink / raw)


Robert I. Eachus wrote:

> This is not necessarily a solution, just trying to understand what you 
> are doing....
> 
> Do you really require that your iterator run on processor A, accessing 
> objects from processor B?  If so it can be done.  But as you sort of 
> point out, the problem is that you are trying to cram everything into 
> one package.

I'm not sure that it is *required*, but that is the approach my mentor 
has been pushing, and it seemed to make some sense, so I was going 
along. I only started learning Ada about 4 or 5 months ago. Classwide 
types is one of the areas that I'm still not solid on.

> 
> If you really need the data transfered from processor to processor, you 
> will need to provide 'Read and 'Write.  These can be defined in terms of 
> the subcomponents for the actual type, see the Rationale, I think for 
> details.
> 
> But I really suspect that you are confusing (in the other meaning of 
> confusing--mixing them together) two different things, a type which is a 
> remote type, and a local iterator over collections of objects of the 
> type.  If the collections are distributed, you have a big design job 
> just defining what iteration means.  (Do you want to iterate over a 
> snapshot of the container state, iterate over all the objects in a 
> particular partition, then do the next partition, iterate over all 
> partitions in parallel, or is there other implicit order of iteration, 
> etc.)
> 

Basically, this program is a client/server program. One server, many 
clients. The server will piece together these COLLECTION_TYPEs, stick 
them in a protected structure, and then the clients will come by and 
process them. But each COLLECTION_TYPE must have its constituent 
elements processed in order. The collection will NOT be modified by the 
server once it is placed into the protected structure for the clients to 
retrieve it from.

It almost sounds like you think that we're doing REMOTE_TYPES for the 
wrong reasons. That is something I started to wonder the other day. If 
it is such a pain in the butt to iterate over a distributed object, 
perhaps that's for a reason? (i.e., you shouldn't) Like I said, I'm 
still not entirely comfortable with classwide types, so I'm not really 
sure how to tell what types you would want to make REMOTE_TYPES and 
which to leave normal and just write 'Read and 'Write for. Are there any 
rules of thumb as to when it is appropriate to make a type a remote 
type? Thanks for your help.

-- Mike L.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with a Remote Type / Iterator
  2003-12-01  3:48 Help with a Remote Type / Iterator Michael Lamarre
  2003-12-01  5:31 ` Robert I. Eachus
@ 2003-12-01 23:00 ` Nick Roberts
  1 sibling, 0 replies; 6+ messages in thread
From: Nick Roberts @ 2003-12-01 23:00 UTC (permalink / raw)


Michael Lamarre wrote:

> package A is
> 
>    pragma REMOTE_TYPES(A);
> 
>    type RECORD_TYPE is tagged limited private;
> 
>    type RECORD_PTR_TYPE is access all RECORD_TYPE'CLASS;
> 
>    -- various operations on RECORD_TYPEs.
> 
> private
> 
>    type RECORD_TYPE is tagged limited record
>       -- Various record fields.
>    end record;
> 
> end A;
> 
> package A.CHILD
> 
>    pragma REMOTE_TYPES(CHILD);
> 
>    type COLLECTION_TYPE(CAPACITY : NATURAL) is tagged limited private;
> 
>    type COLLECTION_PTR_TYPE is access all COLLECTION_TYPE'CLASS;
> 
>    -- Various operations on COLLECTION_TYPEs.
> 
> private
> 
>    type REC_ARRAY_TYPE is array (NATURAL range <>) of RECORD_PTR_TYPE;
> 
>    type COLLECTION_TYPE(CAPACITY : NATURAL) is tagged limited record
>       RECORD_ARRAY : REC_ARRAY_TYPE(1..CAPACITY);
>       -- Various other fields.
>    end record;
> 
> end A.CHILD;

I don't think it is necessary for your COLLECTION_TYPE to be tagged, and I 
don't think it is necessary to export an access type designating it (or 
it's class). I think you only need to export a COLLECTION_TYPE, with a few 
appropriate operations. As a file is essentially a glorified iterator, I 
suggest it is appropriate to look at the Ada.*_IO packages as a starting 
point (these are the nearest thing I can think of as being a standard way 
to iterate over a remote type).

I would also suggest a rule of thumb that might help you. It is generally 
not a useful idea to declare a 'general purpose' access type of a remote 
type in the same specification. For one thing, it is a remote access type; 
this is really rather a special kind of access type, to be used (only) in 
those circumstances when it is especially called for.

Let me now suggest an amended skeleton:

package A is

    pragma REMOTE_TYPES(A);

    type RECORD_TYPE is tagged limited private;

    -- various operations on RECORD_TYPEs.

private

    type RECORD_TYPE is tagged limited record
       -- Various record fields.
    end record;

end A;

package A.CHILD

    pragma REMOTE_TYPES(CHILD);

    type COLLECTION_TYPE is limited private;

    -- Management operations for COLLECTION_TYPE:

    procedure Create (Collection: in out Collection_Type;
                      CAPACITY:   in     NATURAL);

    procedure Copy (Original:  in     Collection_Type;
                    Duplicate: in out Collection_Type);

    procedure Delete (Collection: in out Collection_Type);

    procedure Reset (Collection: in Collection_Type);

    -- Read and Write for COLLECTION_TYPE:

    type RECORD_PTR_TYPE is access [all] RECORD_TYPE'CLASS;

    procedure Write (Collection: in Collection_Type;
                     Item:       in RECORD_PTR_TYPE);

    procedure Read (Collection: in  Collection_Type;
                    Item:       out RECORD_PTR_TYPE);

    function End_of_File (Collection: in Collection_Type) return Boolean;

    -- Other operations on COLLECTION_TYPEs?

    Capacity_Error: exception;

private;

    protected type COLLECTION_HOLDER (CAPACITY : NATURAL) is

       procedure Reset;
       procedure Write (Item: in  RECORD_PTR_TYPE);
       procedure Read  (Item: out RECORD_PTR_TYPE);
       function End_of_File return Boolean;

    private

       Data:    array (1..Capacity) of RECORD_PTR_TYPE;
       Count:   Natural := 0;
       Pointer: Natural := 0; -- 0 for 'end of file'

    end;

    type COLLECTION_TYPE is access COLLECTION_HOLDER;

end A.CHILD;

I hope it's fairly clear how this is intended to work. The most important 
feature is that, instead of having a separate iterator type, I've opted for 
the conceit of allowing one client to iterate over a collection, and if 
another client wishes to do the same (in parallel), it simply makes a copy 
collection of its own (using the Copy procedure). There must be lots of 
alternate designs on this general theme. You may need to introduce 
read/write modes and a more sophisticated Reset procedure.

Since COLLECTION_TYPE is implemented as a remote access type, it hides the 
indirection away from the client. It provides the exported type upon which 
the operations needed by the client can be hung, yet it invisibly allows 
the actual collections -- in objects of the protected type 
COLLECTION_HOLDER -- to be allocated inside the server. You can be sure 
that most implementations of the File_Type in the Ada.*_IO packages are 
(roughly) the same.

Note how I declare RECORD_PTR_TYPE in the CHILD package. It will be a 
remote access type (as it needs to be in this case), but it still makes 
more sense to declare it here, since it is in this package that all the 
operations upon it are also declared. It may, for example, make more sense 
to declare it as a pool-specific type, for this particular use.

-- 
HTH
Nick Roberts




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with a Remote Type / Iterator
  2003-12-01 13:37   ` Michael Lamarre
@ 2003-12-02 23:17     ` Robert I. Eachus
  2003-12-03  4:46       ` Michael Lamarre
  0 siblings, 1 reply; 6+ messages in thread
From: Robert I. Eachus @ 2003-12-02 23:17 UTC (permalink / raw)


Michael Lamarre wrote:

> Basically, this program is a client/server program. One server, many 
> clients. The server will piece together these COLLECTION_TYPEs, stick 
> them in a protected structure, and then the clients will come by and 
> process them. But each COLLECTION_TYPE must have its constituent 
> elements processed in order. The collection will NOT be modified by the 
> server once it is placed into the protected structure for the clients to 
> retrieve it from.

I think I see what you are saying here, but I don't like the way you are 
saying it. ;-)  You have a server which will create collections and pass 
them to clients to process.  Why the change?  With your conditions, 
there is no explicit need for a protected collection type.  The server 
puts together collections and based on some trigger, it passes 
collections to clients to process.   This is easy to model in Ada with 
one server task and many clients.  DO THAT.

First get that working, with entries either where the clients request a 
processing job from the server or with a mechanism for the server to 
call a ready client and pass it data.  Next, change the collection type 
(or whatever parameter type you pass in the task interactions) to a 
remote type, and deal with all the issues of having a program with 
multiple partitions--one server partition and a lot of client partitions.

Does this make for a lot more work?  Not really.  Doing the design first 
as "just" a tasking program, then distributing it will introduce a 
little extra work.  But in my experience it is really worthwhile to 
start the distribution process with a running program, and to be able to 
compare outputs (and timings of course) to insure that the distribution 
part of the system works correctly.  If you can, I would make the 
collection passed to the client partitions a record with an array of 
records.

You don't have to collect the data that way, but why not organize it 
better before sending it between processors?  The advantage is that, 
even if the data structure during accumulation is, say, a linked list, 
the data structure passed between partitions/CPUs is an array (within a 
record) with no explicit or implicit pointers required.

Nick did show how you can create a child package with a remote access 
type, but personally I like to avoid them when possible.

> It almost sounds like you think that we're doing REMOTE_TYPES for the 
> wrong reasons. That is something I started to wonder the other day. If 
> it is such a pain in the butt to iterate over a distributed object, 
> perhaps that's for a reason? (i.e., you shouldn't) Like I said, I'm 
> still not entirely comfortable with classwide types, so I'm not really 
> sure how to tell what types you would want to make REMOTE_TYPES and 
> which to leave normal and just write 'Read and 'Write for. Are there any 
> rules of thumb as to when it is appropriate to make a type a remote 
> type? Thanks for your help.

Yes.  Iterating over a collection of objects of a remote type can mean 
that every object in the collection comes from a different 
partition/processor.  You can do it, and it works.  (In other words, 
remote access types can point between processors.)  But it looks like 
extra overhead because it is.  If you are actually passing collections, 
not individual records, you will usually find that passing them as a 
collection is a lot more efficient.  Of course, if you are doing all 
this on a shared memory architecture system, the collection can be 
passed between partitions by reference instead of by copy.
-- 
                                           Robert I. Eachus

100% Ada, no bugs--the only way to create software.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Help with a Remote Type / Iterator
  2003-12-02 23:17     ` Robert I. Eachus
@ 2003-12-03  4:46       ` Michael Lamarre
  0 siblings, 0 replies; 6+ messages in thread
From: Michael Lamarre @ 2003-12-03  4:46 UTC (permalink / raw)


Robert I. Eachus wrote:
> 
> I think I see what you are saying here, but I don't like the way you are 
> saying it. ;-)  You have a server which will create collections and pass 
> them to clients to process.  Why the change?  With your conditions, 
> there is no explicit need for a protected collection type.  The server 
> puts together collections and based on some trigger, it passes 
> collections to clients to process.   This is easy to model in Ada with 
> one server task and many clients.  DO THAT.

D'oh! You misunderstood. In the server, we are building 
COLLECTION_TYPEs. (And as you allude to later, we are building them as 
lists, but we convert them to array-based structures, but that's beside 
the point.) We then stick the collections into an abstract state machine 
that is an RCI package. There is a protected object in the body of this 
RCI package. The clients "pick up" the collections from the RCI package 
after the server puts them in there. The RCI package is the mechanism by 
which the clients and server synchronize their actions.

> 
> A bunch of other stuff I couldn't possibly address one point at a time...
> 

Sorry to be so unclear about all of this stuff. It is hard to describe a 
problem without talking about the details. Even if I wanted to go into 
details, it would be difficult. So far, this project has taken about 
1500 SLOC, and that is WITH the advantage of being able to leverage a 
bunch of pre-existing infrastructure.

However, I must say, thank you all for your help. I was able to 
implement an ugly looking active iterator. I won't even describe it as 
it is so ugly and embarassing. It isn't much to look at, but it does the 
trick. In the meantime, my mentor took a look at my code to see how I 
had been trying to use the passive iterator we'd implemented earlier.

He suggested implementing an iterator via type extension. There is an 
example of this in the Rationale, though I found it in an online copy of 
the Style Guide at www.adaic.com first. I had seen it before, but didn't 
really understand it until I looked at it again this morning. For now, 
since my software is working, we're putting off changing from my ugly 
active iterator to the type extension iterator for a while. I like the 
type extension iterator though. It offers the safety of a passive 
iterator, but without most of the limitations.

Anyway, we've got it figured out. Thanks to all for your suggestions! 
Hopefully, as I become more skilled in sofware engineering with Ada, I 
can become a helful member of this group. Thanks again.

--Mike L.




^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2003-12-03  4:46 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-12-01  3:48 Help with a Remote Type / Iterator Michael Lamarre
2003-12-01  5:31 ` Robert I. Eachus
2003-12-01 13:37   ` Michael Lamarre
2003-12-02 23:17     ` Robert I. Eachus
2003-12-03  4:46       ` Michael Lamarre
2003-12-01 23:00 ` Nick Roberts

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