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.3 required=5.0 tests=BAYES_00,INVALID_MSGID autolearn=no autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,e94a7e4f6f888766 X-Google-Attributes: gid103376,public From: "Robert I. Eachus" Subject: Re: Self-referential types Date: 1999/10/15 Message-ID: <38079D6F.4F7C00FA@mitre.org>#1/1 X-Deja-AN: 537235859 Content-Transfer-Encoding: 7bit References: <7ttb4a$8mq$1@nnrp1.deja.com> <3802f2db_2@news1.prserv.net> <3803B5E3.F96A6DD4@mitre.org> <3803c8bc_2@news1.prserv.net> <3804E7E0.6A0265FB@mitre.org> <38077EB3.E6911567@mitre.org> <38078775.73450564@pwfl.com> X-Accept-Language: en Content-Type: text/plain; charset=us-ascii X-Complaints-To: usenet@news.mitre.org X-Trace: top.mitre.org 940022843 20941 129.83.41.77 (15 Oct 1999 21:27:23 GMT) Organization: The MITRE Corporation Mime-Version: 1.0 NNTP-Posting-Date: 15 Oct 1999 21:27:23 GMT Newsgroups: comp.lang.ada Date: 1999-10-15T21:27:23+00:00 List-Id: Marin David Condic wrote: > This debate has been around before and a case has been made on the other > side. Similar to the Cobol "perform", nested procedures give you a way of > grouping blobs of code under some sort of descriptive name which helps > clarify the main body of the code - especially where the main body of the > code might otherwise become too deeply nested in control sturctures. But this is the wrong way to do that in Ada. There are two similar cases and several structurally different ways to organize them. First if there is no shared local data common to all of the subprograms, or if tasking is not an issue, you can put the local data in a package body. The package exports the subprograms, and the driver just contains a few calls and perhaps some logic: package Payroll is procedure Read_In_Transaction_Trapping_Device_Errors ( Trans : out Trans_Type); function Transaction_Successfully_Read return Boolean; procedure Edit_Transaction_For_Keypunch_Errors ( Trans : in out Trans_Type); end package Payroll; with Payroll; use Payroll; procedure Process_Payroll is begin --blahblahblah while (not End_Of_File (Trans_File)) loop Read_In_Transaction_Trapping_Device_Errors (Trans) ; if (Transaction_Successfully_Read) then Edit_Transaction_For_Keypunch_Errors (Trans) ; end if ; --yadayadayada end loop ; --blahblahblah end Process_Payroll ; Why is this better? Because it promotes reuse. Other payroll operations can be created which share some, but not all, of the subroutines used by Process_Payroll. The other case, of course, is where you have many payroll objects and need local data for each, whether or not tasking is involved. You can either create payroll objects and store the local data as part of their state, create a task type to represent the instances, or (usually best) create an instance of a generic package for each payroll. The instantiation of this package may be internal to Process_Payroll, or Process_Payroll can be just another declaration in that package. But in any case, the "right" place to keep state in Ada is almost always in packages or tasks, not subprogram bodies. I'll tell you a (now oft-told) story about this. At Honeywell we implemented an in house cross-compiler from Multics to the DPS-6 series. During the implementation, we had no idea whether the best way to find uplevel references in the stack would be via static links or a display. Multics being Multics, we put a counter in the compiler, with a feature to squirrel away the source whenever an uplevel reference was encountered. It also sent mail to the Ada compiler group every morning if it trapped a reference. (The compiler was installed on several Multics machines, but they were all connected to the ARPAnet.) Oh, the compiler also did a full call tree trace to allow the code generator to combine the stack frame of a nested procedure with its parent if the compiler could determine that there were no recursive calls, and no stack objects whose size depended on the parameters to the inner procedure. I finally set the trap off two and half years later, while we were running the ACVC tests. Needless to say, we implemented neither static links or a display, and just left in the code (in the run time) which walked down the call stack until it found the statically containing frame. Potentially very slow if there was an uplevel reference, but as we had shown, wasting even one clock per stack frame created would have been slower on the average. (Note that the 'dynamic' walk was needed for exceptions in any case.) As a result, not only that compiler, but most Ada compilers, are tailored to the expected feature usage. Anyone who violates those assumptions will be penalized by slow code. (Another example is exceptions, in Ada the compiler author will try to lower the cost of creating exception handler scopes at the cost of extra overhead when an exception occurs. Therefore, you are much better off checking in the code for conditions that are not all that rare.) -- Robert I. Eachus with Standard_Disclaimer; use Standard_Disclaimer; function Message (Text: in Clever_Ideas) return Better_Ideas is...