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=-1.9 required=5.0 tests=BAYES_00 autolearn=unavailable autolearn_force=no version=3.4.4 Path: eternal-september.org!reader01.eternal-september.org!reader02.eternal-september.org!news.eternal-september.org!news.eternal-september.org!mx05.eternal-september.org!feeder.eternal-september.org!xmission!newsswitch.lcs.mit.edu!nntp.TheWorld.com!.POSTED!not-for-mail From: Robert A Duff Newsgroups: comp.lang.ada Subject: Re: Elaboration order handling (Was: Bug in 'gnatmake') Date: Thu, 20 Jun 2013 11:11:11 -0400 Organization: The World Public Access UNIX, Brookline, MA Message-ID: References: <7f33982d-3bcf-452e-a3b3-3a0a28505ff1@x20g2000vbe.googlegroups.com> <87r4g0g9c0.fsf@adaheads.sparre-andersen.dk> <87ip1bg4z2.fsf_-_@adaheads.sparre-andersen.dk> <53d0b070-a03b-43d0-a560-68dd3a8bebf5@googlegroups.com> <51c218df$0$6623$9b4e6d93@newsspool2.arcor-online.net> NNTP-Posting-Host: shell01.theworld.com Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Trace: pcls6.std.com 1371741072 12905 192.74.137.71 (20 Jun 2013 15:11:12 GMT) X-Complaints-To: abuse@TheWorld.com NNTP-Posting-Date: Thu, 20 Jun 2013 15:11:12 +0000 (UTC) User-Agent: Gnus/5.1008 (Gnus v5.10.8) Emacs/21.3 (irix) Cancel-Lock: sha1:xNZ+cVEp3a/gNLl4D1rP2qYqgh0= Xref: news.eternal-september.org comp.lang.ada:15865 Date: 2013-06-20T11:11:11-04:00 List-Id: Jeffrey Carter writes: > Since we're discussing elaboration order, there's a case that I wonder about: A case of mutually-recursive packages. That's unusual, because it's usually better to design software in layers, where higher layers use the lower layers, but not vice-versa. But sometimes such mutually-dependent packages are exactly the right thing. > with B; > > package A is > function F (I : Integer) return B.Thing; > > function R return Integer; > end A; > > package body A is > function F (I : Integer) return B.Thing is > -- null; > begin -- F > return B.To_Thing (I); > end F; > > function R return Integer is > -- null; > begin -- R > return 7; > end R; > end A; > > package B is > type Thing is private; > > function To_Thing (I : Integer) return Thing; > private -- B > type Thing is new Integer; > end B; > > with A; > > package body B is > function To_Thing (I : Integer) return Thing is > -- null; > begin -- To_Thing > return Thing (I); > end To_Thing; > > C : constant Integer := A.R; > end B; In standard Ada, the above is perfectly legal, and does not raise Program_Error. > It seems to me there's a valid elaboration order for these: > > * spec of B > * spec of A > * body of A > * body of B Yes, and that is the only order allowed by the RM. > I've never been able to get such code to bind, though. Is there some way > to get this accepted, or is it illegal Ada? Without -gnatE, GNAT will complain about an elaboration cycle, because it is inserting an implicit "pragma Elaborate_All(A);" on the body of B. It does that because it's trying to preserve abstraction -- it wants the code to work no matter what A.R does (it's not looking at the body of A.R while compiling body of B). In fact, A.R could have called A.F, in which case the program is broken -- the only allowed order causes Program_Error in standard Ada, and the whole point of the not-gnatE mode is to do all such run-time checks statically. Imagine adding that call to A.F during maintenance. And the reason the implicit pragma causes a cycle is that Elaborate_All is transitive -- it requires the body of B to be elaborated before the body of B, which is impossible. But you've got mutual recursion here, so A and B are necessarily tightly coupled, and you, the programmer, can know that A.R does NOT call anything in B. In that case, you can solve the problem by putting "pragma Elaborate(A);" on the body of B. GNAT uses that Elaborate *instead* of the implicit Elaborate_All, and Elaborate is nontransitive, so it all works, using the order you showed above. But be careful: If you later change A.R to call A.F, you'll be in trouble. The other way to get this example to work is to use -gnatE. I don't recommend that. - Bob P.S. I don't like your convention of putting "-- null;" in empty declarative parts! Comments should impart useful information, and empty declarative parts are nothing special, and anyway, I can see it's empty without a comment.