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.8 required=5.0 tests=BAYES_00,INVALID_DATE autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 1108a1,93fa00d728cc528e X-Google-Attributes: gid1108a1,public X-Google-Thread: 103376,93fa00d728cc528e X-Google-Attributes: gid103376,public X-Google-ArrivalTime: 1994-10-19 04:58:38 PST Newsgroups: comp.lang.ada,comp.object Path: bga.com!news.sprintlink.net!howland.reston.ans.net!pipex!uunet!noc.near.net!ray.com!news.ray.com!news.ed.ray.com!swlvx2!jgv From: jgv@swl.msd.ray.com (John Volan) Subject: Re: SOLVED! Decoupled Mutual Recursion Challenger Date: Mon, 17 Oct 1994 15:48:12 GMT Message-ID: <1994Oct17.154812.9104@swlvx2.msd.ray.com> References: <1994Oct12.224944.25566@swlvx2.msd.ray.com> Sender: news@swlvx2.msd.ray.com (NEWS USER) Organization: Raytheon Company, Tewksbury, MA Xref: bga.com comp.lang.ada:7081 comp.object:7542 Date: 1994-10-17T15:48:12+00:00 List-Id: In article <1994Oct12.224944.25566@swlvx2.msd.ray.com> I (John Volan) wrote: > Now let's go back and consider how to implement the Identity package. > To implement the Identity.Value type, all we need is some kind of > "black box" that is guaranteed to be the same storage size as an > access type. Almost anything would do, but System.Address seems the > most convenient for this purpose. > (Er ... I've been scouring the RM9X 5.0 and much to my surprise I can't > seem to find positive confirmation for the fact that System.Address will > have the same bit-representation as access types. Tucker, if you're > listening, can you give me a hand here?) Actually, there wasn't any need to involve System.Address after all. A better solution would be to just declare Identity.Value as an access type pointing to some "dummy" designated type. [Thanks to Tim Coslet for pointing out this possibility to me.] Here's an improved spec for package Identity. The public part is identical to my previous solution, so it still provides a reusable way of achieving mutual recursion in a decoupled fashion: ---------------------------------------------------------------------- generic package Identity is -- Identity.Value type Value is private; -- Identity.None None : constant Identity.Value; -- Identity.Translation generic type Object (<>) is limited private; -- matches any type type Pointer is access Object; package Translation is -- Identity.Translation.To_Pointer function To_Pointer (The_Identity : in Identity.Value) return Pointer; pragma Inline (To_Pointer); -- Identity.Translation.To_Identity function To_Identity (The_Pointer : in Pointer) return Identity.Value; pragma Inline (To_Identity); end Translation; private -- Identity type Void is null record; -- "dummy" designated type -- Identity.Value type Value is access Void; -- Identity.None None : constant Identity.Value := null; end Identity; ---------------------------------------------------------------------- Implementing Identity.Value an access-to-dummy-Void-type has the following advantages: (1) It avoids portability problems. It's conceivable that a given Ada compiler might not implement System.Address the same as access types. However, it is a safe bet that all access types will be implemented the same way (within a given Ada implementation). (2) It avoids coupling the Identity package to package System. (3) It still preserves type-safety, because an Identity.Value will never actually be used *as* an access-to-dummy-Void. (Identity.Value is still a "black box", after all.) (4) The default initialization of Identity.Values to Identity.None is implemented directly in terms of the default initialization of access types to null. There's no need to muck around with a record type. (5) The bodies of the Translation functions can be implemented directly as instantiations of Unchecked_Conversion, since Ada9X allows renaming declarations to act as subprogram bodies: ---------------------------------------------------------------------- with Ada.Unchecked_Conversion; package body Identity is One_Translation_Registered_Already : Boolean := False; ----------------------- -- Identity.Translation ----------------------- package body Translation is function Identity_To_Pointer is new Ada.Unchecked_Conversion (Identity.Value, Pointer); function Pointer_To_Identity is new Ada.Unchecked_Conversion (Pointer, Identity.Value); ---------------------------------- -- Identity.Translation.To_Pointer ---------------------------------- function To_Pointer (The_Identity : in Identity.Value) return Pointer renames Identity_To_Pointer; ----------------------------------- -- Identity.Translation.To_Identity ----------------------------------- function To_Identity (The_Pointer : in Pointer) return Identity.Value renames Pointer_To_Identity; -- Since To_Pointer and To_Identity are really just instantiations of -- Unchecked_Conversion, and since Unchecked_Conversion is intrinsic, -- the cost of calling these subprograms very likely will be *zero*. begin -- Translation if One_Translation_Registered_Already then raise Standard.Program_Error; else One_Translation_Registered_Already := True; end if; end Translation; end Identity; ---------------------------------------------------------------------- (Well, folks, it just keeps looking better and better ... :-) --John Volan -------------------------------------------------------------------------------- -- Me : Person := (Name => "John Volan", -- Company => "Raytheon Missile Systems Division", -- E_Mail_Address => "jgv@swl.msd.ray.com", -- Affiliation => "Enthusiastic member of Team Ada!", -- Humorous_Disclaimer => "These opinions are undefined " & -- "by my employer and therefore " & -- "any use of them would be " & -- "totally erroneous."); --------------------------------------------------------------------------------