From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=0.7 required=5.0 tests=BAYES_00,INVALID_DATE, REPLYTO_WITHOUT_TO_CC autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,7a4380ff535aa24d X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 1994-12-02 18:20:59 PST Path: bga.com!news.sprintlink.net!howland.reston.ans.net!pipex!uunet!newsgate.watson.ibm.com!watnews.watson.ibm.com!ncohen From: ncohen@watson.ibm.com (Norman H. Cohen) Newsgroups: comp.lang.ada Subject: Re: cross linking packages Date: 2 Dec 1994 14:30:52 GMT Organization: IBM T.J. Watson Research Center Distribution: world Message-ID: <3bnb2s$1ej1@watnews1.watson.ibm.com> References: <3bg8mp$i0g@gnat.cs.nyu.edu> <3bj0br$mri@network.ucsd.edu> Reply-To: ncohen@watson.ibm.com NNTP-Posting-Host: rios8.watson.ibm.com Date: 1994-12-02T14:30:52+00:00 List-Id: In article <3bj0br$mri@network.ucsd.edu>, mbk@inls1.ucsd.edu (Matt Kennel) writes: |> Can somebody answer this question: |> |> Why were cyclical dependencies among types defined illegal? |> |> (I.e. type A defines features that use type B, and type B defines |> features that use type A.) ... |> |> It apparently works fine when they are in the same package. |> Thus supposing you put two types each in their own package, both inside |> an outer package. |> |> Do the mutual dependencies now work fine because they are both inside |> one package, the outer one? It is straightforward to define different types in a mutually recursive data structure in two or more packages. The following works in Ada 83 or Ada 9X: package A_Package is type A is private; ... private type A_Node; -- incomplete type declaration, completed in body type A is access A_Node; end A_Package; package B_Package is type B is private; ... private type B_Node; -- incomplete type declaration, completed in body type B is access B_Node; end B_Package; with B_Package; package body A_Package is type A_Node is record ... B_Part: B_Package.B; ... end record; ... end A_Package; with A_Package; package body B_Package is type B_Node is record ... A_Part: A_Package.A; ... end record; ... end B_Package; In this case both package bodies depend on both package declarations, but the package declarations do not depend on each other, so there is no circularity. The difficulty the original questioner had was not in defining a mutually recursive DATA STRUCTURE, but mutually recursive INTERFACES: with B_Package; |with A_Package; package A_Package is |package B_Package is type A is ...; | type B is ...; procedure Op | procedure Op (...; X: in B_Package.B; ...);| (...; X: in A_Package.A; ...); ... | ... end A_Package; |end B_Package; There is no way to do this without making each of the package declarations dependent on the other. In Ada 9X, a way out is to make A and B tagged types derived from abstract tagged types declared elsewhere, and to replace references to A and B in each others' interfaces by references to the parent types' classwide types, thus eliminating the circular dependences between the A_Package declaration and the B_Package declaration. The circularity presents a difficulty because Ada programs are compiled and checked for consistency incrementally, a compilation unit at a time. It was a principle design goal of Ada to facilitate the development of huge programs in this manner, with each compilation unit checked, when it is compiled, for consistency with all units whose facilities it uses. This requires that units be compiled in some order such that all declarations of facilties to be provided by a unit have been compiled before all uses of those facilities. It might be possible, in theory, to rewrite the language rules to allow the mutually dependent declarations of A_Package and B_Package by deferring all consistency checks and code generation until all required packages had been compiled. However, this would violate the requirement for incremental recompilation and rechecking of small pieces of a program and return us to the era of "big bang" integration of modules compiled in isolation from each other. Allowing ciruclarity in with clauses would make it possible for other embarassing circularities to arise, and some way would have to be found to deal with those: with B_Package; |with A_Package; package A_Package is |package B_Package is type A is | type B is array (1 .. B_Package.B'Last) | array (1 .. A_Package.A'Last) of Integer; | of Integer; ... | ... end A_Package; |end B_Package; |> After all in a statically typed langauge like Ada, all variables |> must be bound to types statically at compile time, so there |> should be no ambiguity in "elaboration order" as there is no |> run-time execution that must take place to bind variables |> to types. The type of a variable is indeed a compile-time property, but the size of a type (and thus the code that must be generated to manipulate it efficiently) is not. Type declarations are "elaborated" (executed) at run time. Given a function Next_Number_In_Input_File that reads and returns a value from an input file, for example, a type can be declared as type T is array (1 .. Next_Number_In_Input_File) of Integer; -- Norman H. Cohen ncohen@watson.ibm.com