* 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