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,99ab4bb580fc34cd X-Google-Attributes: gid103376,public From: adam@irvine.com (Adam Beneschan) Subject: Re: Q: access to subprogram Date: 1996/07/03 Message-ID: <4re8bj$qfk@krusty.irvine.com>#1/1 X-Deja-AN: 163540988 references: <4rd5lu$q4@mulga.cs.mu.OZ.AU> organization: /z/news/newsctl/organization newsgroups: comp.lang.ada Date: 1996-07-03T00:00:00+00:00 List-Id: It should be noted that the new object-oriented features of Ada 95 should make subprogram accesses less necessary than before. Abstract types inherently possess subprogram pointers, so it should be possible to take advantage of this feature as an alternative to explicit subprogram accesses. In Ada 83, I missed being able to do things like this: with Pack1; procedure P1 is Error_File : Text_IO.File_Type; procedure Report_Error (Message : string) is begin Text_IO.Put_Line (Error_File, Message); end Report_Error; begin Text_IO.Create (Error_File, ... ... Pack1.Do_Some_Big_Procedure_That_Can_Report_Errors (Report_Error); -- some people would fire me for using a name like this :) ... end P1; The purpose is to call a procedure that can generate error messages, and to tell it what I want done with those error messages. Things can't be done this way in Ada 83. The problem can be solved using generics in Ada 83, but I've always thought of this as a strange reason for using generics, and it can get hairy (suppose, for example, that the big procedure calls another procedure that also reports errors; now that procedure has to be turned into a generic also, and so on). In Ada 95, you can accomplish this with a subprogram access, but you have to make Report_Error global, and therefore Error_File has to be made global also. So doing things this way forces you to give up some of the design advantages of using local variables. (It isn't too big a problem in the above example, but in more complicated situations, making things global can be a real pain.) This is also one of the things I missed when I was programming in C, since C doesn't have nested procedures. Another way to do this is with an abstract type. (PLEASE NOTE: I don't guarantee that my Ada 95 syntax is correct!) You can declare an "error handler" in some global package like this: type Error_Handler is abstract tagged null record; procedure Handle_Error (Handler : in Error_Handler; Message : in string) is abstract; The Do_Some_Big_Procedure_That_Can_Report_Errors can then take an Error_Handler (or Error_Handler'Class?) as a parameter. It calls the Handle_Error routine when it wants to generate an error message. It can pass the Error_Handler object around to other procedures that also report errors. P1 sets things up to use its own error reporting routine as the error handler: procedure P1 is type My_Error_Handler is new Error_Handler with record Error_File : Text_IO.File_Type; end record; EH : My_Error_Handler; -- variable name chosen to avoid being fired :) procedure Handle_Error (Handler : in My_Error_Handler; Message : in string) is begin Text_IO.Put_Line (Handler.Error_File, Message); end Handle_Error; begin Text_IO.Create (EH.Error_File, ... ... Pack1.Do_Some_Big_Procedure_That_Can_Report_Errors (EH); This mechanism doesn't let you *directly* store an access to a subprogram in a global variable, the way subprogram accesses do; but using accesses to Error_Handler objects should let you accomplish the same thing. Once again, my apologies if my Ada 95 syntax is incorrect. I haven't yet learned all the nuances of Ada 95 programming. Mainly, I wanted to discuss the concepts involved; someone else may need to fill in the programming details. -- Adam