From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.5-pre1 (2020-06-20) on ip-172-31-74-118.ec2.internal X-Spam-Level: X-Spam-Status: No, score=-1.9 required=3.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.5-pre1 Date: 4 May 93 13:59:32 GMT From: cis.ohio-state.edu!magnus.acs.ohio-state.edu!usenet.ins.cwru.edu!howland. reston.ans.net!noc.near.net!inmet!spock!stt@ucbvax.Berkeley.EDU (Tucker Taft) Subject: Re: Passing procedures as parameters to procedures. Message-ID: List-Id: In article <1s5gae$kr4@huon.itd.adelaide.edu.au> andrewd@cs.adelaide.edu.au writes: >> First Ada9x is adding access to procedure/function types so that is a >> non-problem in Ada9x. > >Yes, and very welcome, too. If any of the 9X heavies can explain to me >why this has to be done in terms of access types, though, I'd be >grateful. The fact that this is done in terms of a procedure closure >is an implementation detail, it seems to me. One person's "implementation detail" is another person's "fundamental semantic model." There are certainly languages where procedures are first class objects, and can be freely assigned, passed around, returned from functions, etc. Such languages (e.g. Scheme) typically require garbage collection, and the ability to have the activation record for a subprogram on the heap. This is all well and good, but our view is that Ada is not trying to compete with such languages. Ada has already been accused of trying to be all things to all people. Our view is that Ada is intended as a systems programming language, where the programmer has complete understanding and complete control over the implementation. It is great if it ends up as a generally useful language for the implementation of other kinds of programs, but we believe it is important to keep a clear focus on our primary market of systems programming. Little if anything is an "implementation detail" to a systems programmer, especially a real-time systems programmer. If a programmer wants to introduce a level of abstraction, it should be done by defining an abstract data type (ADT), but it is still important to be able to implement such an ADT in efficient, concrete terms. Given the above philosophy, we believe it is appropriate that the language be consistent with the implementation model. Clearly a subprogram "variable" is not a holder for code. It is a reference to code. In Ada 83, storable references are called access values. It is true that if all we wanted to allow were parameters that referred to subprograms, there would be no reason to think of them as access values, since Ada 83 already allows "implicit" references as part of parameter passing. But if one is going to have storable references to code, allowing for arrays of such references, etc., it is important that one recognize that these are semantically like references (i.e. access values), not like copies. Furthermore, from the point of view of the semantic model, it is essential to recognize that there is a possibility of dangling references (in the absence of heap allocation of activation records). This same problem exists with "normal" access-to-object values in Ada 9X, because one is allowed to "point" to declared objects (so long as they are marked "aliased"). It is simpler to associate checks designed to prevent dangling references with access types in general, rather than having some with access-to-object types, and some with "subprogram types." One final reason to avoid the term "subprogram type" -- one would inevitably relate them to "task type." But they are completely different from task types. A task type is a template for a task. All instances of a task type are associate with the same code body. The only difference is the data associated with them. The analogous "subprogram type" would have similar properties, and be essentially useless. Now one could alternatively argue that task types ought to be changed, to make them more like the Ada 9X access-to-subprogram types, specifying only an interface, allowing variables of such a type to refer to task objects with any associated code body, so long as they had a matching interface. Not a bad idea, but then one would probably want to view them as access-to-task types, since one would presumably want to have assignable variables of such a type. In any case, hopefully this rambling discussion exposes some of the reasons we chose to make them access-to-subprogram types. As mentioned above, we would agree that "subprogram types" would make sense if either they were limited to being parameters only, or if they were truly "first-class" objects with heap allocation of activation records. However, the user requirement seemed to be for an assignable reference to a subprogram, which in our view, is clearly a better fit for an "access-to-subprogram" type rather than a "subprogram type." > . . . >In Ada9X the answer will look like this: > >type d_proc is access procedure; >type b_proc is access procedure(c : d_proc); > >procedure a(b : b_proc) is > procedure d is > begin > null; > end; >begin > b(d'access); I hate to be the one to break the news, but this is not legal Ada 9X. Since the access type is declared at the outermost level, so must be the designated procedure. Hence, you must declare "d" outside of "a". Otherwise, there would be nothing preventing someone storing away the reference to "d" in some global variable of type "d_proc," which would become a dangling reference as soon as "a" returned. One could move this kind of "accessibility" check to the assignment to the global, but that would require that all access-to-subprogram values carry around an "accessiblity level" indicator of some sort. It would also mean that the check would move from being a compile-time check to being a run-time check, which is always less safe. Alternatively, one could have two kinds of access-to-subprogram types, one "limited" and only usable for parameters (no assignment), and one "nonlimited," permitting assignment, etc. We considered this, but it was ultimately rejected as unnecessary complexity. Perhaps if you had a more complete example showing how generics can't solve this important class of problems, there would be more sympathy for providing some mechanism addressing this issue. >end; > >procedure x(y : d_proc) is >begin > y.all; >end; >. >. >. >a(x'access); >. >. >. > >BTW, this example comes from real, working and useful Pascal code, not >(as some might think) from a contest on obfuscated Pascal! Must "d" be a nested procedure, or was it just the normal Pascal tendency to nest things? >Happy programming. ># Andrew Dunstan # There's nothing good or bad # ># net: # # ># adunstan@steptoe.adl.csa.oz.au # but thinking makes it so. # ># or: andrewd@cs.adelaide.edu.au # # S. Tucker Taft stt@inmet.com Ada 9X Mapping/Revision Team Intermetrics, Inc. Cambridge, MA 02138 USA