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 Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!mnetor!seismo!lll-lcc!mordor!styx!ames!ucbcad!ucbvax!lll-icdc.arpa!wilson%anchor.DECnet From: wilson%anchor.DECnet@lll-icdc.arpa ("ANCHOR::WILSON") Newsgroups: comp.lang.ada Subject: Pre-elaboration Problems Message-ID: <8701010253.AA21054@ucbvax.Berkeley.EDU> Date: Mon, 29-Dec-86 22:27:00 EST Article-I.D.: ucbvax.8701010253.AA21054 Posted: Mon Dec 29 22:27:00 1986 Date-Received: Thu, 1-Jan-87 00:41:43 EST Sender: daemon@ucbvax.BERKELEY.EDU Reply-To: "ANCHOR::WILSON" Organization: The ARPA Internet List-Id: I have run into a problem with Ada and both of the solutions I have found bother me. I have a generic package which a user (i.e., programmer) can use to easily perform DECnet network I/O. The package can support many similtaneous I/O channels. The package imports a MESSAGE_TYPE and a HANDLE_MESSAGE procedure and exports an ADDRESS_TYPE and a SEND procedure. Here's the spec.: package NET_READER is type ADDRESS_TYPE is private; generic type MESSAGE_TYPE is private; with procedure HANDLE_MESSAGE( FROM : in ADDRESS_TYPE; MESSAGE : in MESSAGE_TYPE ); package READER is procedure SEND( TO : in ADDRESS_TYPE; MESSAGE : in MESSAGE_TYPE ); end READER; private . . . end NET_READER; The idea is that the package user just needs to supply a HANDLE_MESSAGE procedure and all the network stuff will be taken care of for him. It is expected that HANDLE_MESSAGE will sometimes call SEND to send a reply back to the originator of the current message. The user program looks something like this: with NET_READER; procedure TEST is procedure HANDLE_MESSAGE( FROM : in NET_READER.ADDRESS_TYPE; MESSAGE : in MESSAGE_TYPE ); package NET is new NET_READER.READER( INTEGER, HANDLE_MESSAGE ); procedure HANDLE_MESSAGE( FROM : in NET_READER.ADDRESS_TYPE; MESSAGE : in MESSAGE_TYPE ) is begin ... NET.SEND ... end HANDLE_MESSAGE; begin null; end TEST; The problem is this: if a message is "waiting at the door," HANDLE_MESSAGE gets called before it is elaborated, resulting in a PROGRAM_ERROR. This is because the declarative part of TEST is elaborated in top-to-bottom order. Unfortunately, HANDLE_MESSAGE needs visibility of NET to call SEND. My solutions are these: 1) Put a loop and an exception handler in the body of NET_READER.READER and wait for PROGRAM_ERROR to go away. 2) Put a START procedure in NET_READER.READER which the user has to call to start things up. Solution 1 is a problem for a few reasons. Should the loop be infinite? How long should we wait? What if the user's HANDLE_MESSAGE routine is raising another kind of PROGRAM_ERROR and we're just getting a propogated version? The nice side of this way is that all the messy details are hidden in the package body. The user couldn't care less about the order of elaboration, and likely won't understand the problem in the first place. Solution 2 has the problem of requiring explicit action on the user's part. START looks like an initialization routine, and in all the rest of our packages initialization is done inside the package. Asthetically, we loose the "begin null; end" main program body which has looked so appealing. A more general problem is one where the generic package imports a user routine and doesn't export anything. In this case, the user could order his declarative part such that the package instantiation comes after the procedure body, but *I* wouldn't have naturally done that anyway. I'd have made the forward declaration of my procedure just so all my declarations would appear together on a small page. Then, everything would have worked nicely until the window was hit a few months down the road . . . . My questions to the Ada community are these: o Is there a Solution 3? o Can anyone make me feel better about Solutions 1 or 2? o How can I convince myself that my program isn't some day going to call an unelaborated routine? Is there a simple checklist I can use? Finally, why don't I get a PROGRAM_ERROR on the following program? It seems like as soon as the main task has elaborated task T, T should start running (given the higher priority) before P is elaborated . . . . (I compiled and ran this using VAX Ada on a VAX 11/750.) with TEXT_IO; use TEXT_IO; with SYSTEM; procedure TEST_1 is task T is pragma PRIORITY( SYSTEM.PRIORITY'last ); end T; procedure P; task body T is begin P; end T; procedure P is begin PUT_LINE( "Hi!" ); end P; begin null; end TEST_1; Thanks for your interest, --- Rick Wilson wilson%anchor.decnet@lll-icdc.arpa (415) 423-6662 ------