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!mx02.eternal-september.org!.POSTED!not-for-mail From: Natasha Kerensikova Newsgroups: comp.lang.ada Subject: Generic instantiation before actual subprogram body Date: Thu, 4 Dec 2014 08:48:58 +0000 (UTC) Organization: A noiseless patient Spider Message-ID: Injection-Date: Thu, 4 Dec 2014 08:48:58 +0000 (UTC) Injection-Info: mx02.eternal-september.org; posting-host="76a49b86bc3e16725b7cfca3d85cb4c8"; logging-data="19745"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX1+7m2XUOhvLnJT5Z2JQezgC" User-Agent: slrn/1.0.1 (FreeBSD) Cancel-Lock: sha1:AbHqMFvf2txsy0Icxn9PkQUEjNY= Xref: news.eternal-september.org comp.lang.ada:23856 Date: 2014-12-04T08:48:58+00:00 List-Id: Hello, I have fallen into the pattern of refactoring common using generics instead of cut-and-paste. One of my earliest example of this is https://github.com/faelys/natools/blob/trunk/src/natools-s_expressions-interpreter_loop.adb I think it's a good thing, even for only a few tens of lines of code, mostly for readers who discover the code: explicit common patterns reduce (I think) the cognitive overhead. Please enlighten me if I'm wrong on this. At some early point when I used the pattern, I encountered a GNAT warning telling that a particular generic instantiation would raise Program_Error at run-time because the body of actual subprograms in the instantiation were found later in the source text. Since then, I always put instantiations after the bodies of the actual subprograms, even though it makes it a bit awkward. A lot of time passed, and I'm now feeling the need to refactor a cut-and-paste-able code structure involved in a recursive cycle. Recursivity means at some point something has to be called before its body. This led me to question that instantiation-before-body warning, so I started experimented, but I couldn't reproduce the warning. My question is now, in which set of circumstances is it allowed (or forbidden) to instantiate a generic with a subprogram whose body has not yet been seen by the compiler? I'm pretty sure I was using an older GNAT in Ada 2005 mode back then, could it be something that has changed in Ada 2012? I tried to read the ARM and then the AARM, on chapters related to generic instantiation and/or subprogram elaboration (I can't think of any not-elaboration-related reason to raise Program_Error because of subprogram body position in the source). I also tried reading GCC sources, looking for "Program_Error [" and "body seen". However all these resources are way out of my depth, so I'm asking here. On a related but almost out-of-topic point, I have always instantiated generic on a nesting level as shallow as possible. This is due to some superstitious fear about trampolines and accessibility levels and a few other nesting-related concept I don't understand. In the particular case of my alternative-to-cut-and-paste generics, it's often a generic procedure, whose instances are each called only once, in a public subprogram whose body consists of almost only the generic instance call, sometimes with a little bit of argument shuffling or type adjustments to fit the generic model when the API has a slightly different logic. For example I have somewhere code similar to: package body Whatever is procedure Append (...); procedure Render_Page_Element (...); procedure Render_Page is new Natools.S_Expressions.Interpreter_Loop (Output_Accumulator, Page_Type, Render_Page_Element, Append); procedure Public_Render (Page : in Page_Type; Output : in out Output_Accumulator; Template : in out Natools.S_Expressions.Lockable.Descriptor'Class) is begin Render_Page (Template, Output, Page); end Public_Render; end Whatever Wouldn't it be better in such a case to instantiate the generic inside Public_Render? That would solve any elaboration issue, and that would limit the scope of the generic instance to where it is actually use, which I find is generally a good guideline to follow. I guess the compiler can easily tell there is no special nesting mechanism needed, since all actual parameters have a large scope. Is there any particular rational reason to prefer top-level instantiation to nested instantiation, or vice versa? Thanks in advance for your insights, Natasha