klaiber@udel.EDU (Alexander Klaiber) (07/08/87)
HELP!!!!! I am doing a high-level comparison of high-level languages and I've run into a severe problem with Ada. What I am trying to do is the following: Assume I have a generic package linked_list that, given some type "item", defines a type "list" which is a list of "item". I want to write a package that defined two types, A and B and operations on these. Now my problem is that both A and B are records and A includes a field of type "list of B" and B includes a field of type "list of A". I want the lists to be handled by the generic linked_list. However, the following obviously doesn't work: package my_package is type A is private; type B is private; package list_of_A is new linked_list(A); -- ** problem ** package list_of_B is new linked_list(B); -- ** problem ** -- operations on A/B and "list of A"/B go here private type A is record xxx : list_of_A.list; end record; type B is record xxx : list_of_B.list; end record; end my_package; My compiler complains about A/B not being fully defined in the generic instantiation of linked_list. As Ada doesn't seem to support cyclic import, I see no way of splitting up this package. Note that I always can define the "list of A/B" explicitly by using type A is record xxx : ptr_to_B_node; end; (other type declarations here) and writing procedures to handle the lists. However, this would (a) prevent me from using the already existing generic package and (b) I would have to include two copies of list-handlers, one for "lists of A" and one for "lists of B". This would make Ada look unnecessarily bad. Any ideas how to work around this problem? P.S. I haven't been programming in Ada all too long, so I may be overlooking the obvious... Alexander Klaiber klaiber@dewey.udel.edu
stt@ada-uts (07/10/87)
A solution is to pass an access-to-A as the generic actual type, or include an access-to-list-header as the component of B (and move the instantiations down below the full record type definitions). However, your best solution is probably to define A and B as access types themselves, and defer the whole data structure definition to the package body (see 3.8.1:3), as follows: type A is private; type B is private; . . . private type A_Record; -- full definition deferred to package body type A is access A_Record; type B_Record; -- full definition deferred to package body type B is access B_Record; end pkg; package body pkg is <instantiations> type A_Record is B_List : List_Of_B.List; . . . This also saves you greatly on recompilations when you decide to add or change component definitions within A_Record or B_Record. Tucker Taft c/o Intermetrics, Inc. Cambridge, MA 02138 P.S. Here is a rationale for the restrictions... Mutually recursive types clearly require the use of access types somewhere. You have hidden the use within the generic. This conflicts with the general rule that the legality of an instantiation is determined by the legality of the generic itself and the legality of the actual/formal parameter matching. (The only error which cannot be detected until the actual parameter substitution takes place within the spec and body of the generic has to do with the use of unconstrained types (see 12.3.2:4).) Allowing uncompleted private types as actual parameters as in your example would severely increase the number of error situations which could only be determined upon parameter substitution. In your example it would be illegal if a list header included an instance of the item type directly, whereas if a list header included only an access type, then it would be legal.
cjh@petsd.UUCP (Chris Henrich) (07/15/87)
In article <322@louie.udel.EDU> klaiber@udel.EDU (Alexander Klaiber) writes: >HELP!!!!! >I am doing a high-level comparison of high-level languages and I've run >into a severe problem with Ada. What I am trying to do is the following: > >Assume I have a generic package linked_list that, given some type "item", >defines a type "list" which is a list of "item". > >I want to write a package that defined two types, A and B and operations on >these. Now my problem is that both A and B are records and A includes a >field of type "list of B" and B includes a field of type "list of A". I >want the lists to be handled by the generic linked_list. The following pattern is acceptable to at least one validated compiler (that of Concurrent Computer Corp.): PACKAGE my_package_1 IS TYPE a; -- "incomplete type declarations" TYPE b; TYPE a_ptr IS ACCESS a; -- about the only thing you can do with TYPE b_ptr IS ACCESS b; -- incomplete type declarations PACKAGE list_of_a_ptr IS NEW linked_list ( a_ptr ); PACKAGE list_of_b_ptr IS NEW linked_list ( b_ptr ); TYPE a IS RECORD xxx: list_of_b_ptr . list; END RECORD; TYPE b IS RECORD xxx: list_of_a_ptr . list; END RECORD; --- more declarations, including operations on types "a" and "b" END my_package_1; Note that your linked lists come out as lists of pointers. This design is open to criticism, because it makes both the record structure and the pointers visible to users of the package. There is some advantage to be gained from keeping the innards of "a" and "b" private. For one thing, increased freedom in using them to instantiate other generic units. For another, it allows you to separate the compilation of "a" and "b". Here is a scheme that is a little better from the viewpoint of software engineering: PACKAGE my_package_2_a IS TYPE abstract_a IS PRIVATE; -- fundamental operations with abstract_a PRIVATE TYPE record_a; TYPE abstract_a IS ACCESS record_a; END my_package_2_a; PACKAGE my_package_2_b IS TYPE abstract_b IS PRIVATE; -- fundamental operations with abstract_b PRIVATE TYPE record_b; TYPE abstract_b IS ACCESS record_b; END my_package_2_b; -- note how the implementation of "a" depends on the *specification* -- of "b" WITH my_package_2_b; USE my_package_2_b; WITH linked_list; PACKAGE BODY my_package_2_a IS PACKAGE linked_list_b IS NEW linked_list ( abstract_b ); TYPE record_a IS RECORD xxx: linked_list_b.list; END RECORD; -- lots of other implementation details END my_package_2_a; WITH my_package_2_a; USE my_package_2_a; WITH linked_list; PACKAGE BODY my_package_2_b IS PACKAGE linked_list_b IS NEW linked_list ( abstract_b ); TYPE record_b IS RECORD xxx: linked_list_b.list; END RECORD; -- list of other implementaiton details END my_package_2_b; Hope this helps. Regards, Chris -- Full-Name: Christopher J. Henrich UUCP: ...!hjuxa!petsd!cjh US Mail: MS 313; Concurrent Computer Corporation; 106 Apple St; Tinton Falls, NJ 07724 Phone: (201) 758-7288 Concurrent Computer Corporation is a Perkin-Elmer company.