Install_Handler(Handler => MyHandler'Unrestricted_Access);
Unlike some languages, to get an access or "reference" or "pointer" to a procedure, you have to be explicit by using the 'Access
attribute. It's a bit like using &func
in C to get a pointer to a function, but C allows you to omit the &
. Ada doesn't allow for that kind of shorthand, in part because Ada doesn't require parentheses when calling a procedure/function with no parameters, which means that using the name alone would be syntactically ambiguous.
In many cases, using 'Access
would be good enough. The reason it isn't enough here, is because of Ada's accessibility rules. Suppose you write something like
procedure Spam is
Number_Of_Vikings : Integer := 0;
procedure MyHandler is
begin
Put_Line("YOU WILL NEVER END MY SPAM");
Number_Of_Vikings := Number_Of_Vikings + 1;
end MyHandler;
begin
Install_Handler(Handler => MyHandler);
--while True loop
for I in 1 .. 10 loop
Put_Line("SPAM SPAM SPAM SPAM SPAM SPAM");
end loop;
end Spam;
In theory, Install_Handler
could store the Handler
parameter in a global, which means that (in theory) something else could use the access-to-procedure global to call MyHandler
after the Spam
procedure has returned. Then, MyHandler
would try to do something with Number_Of_Vikings
. But that variable would no longer exist, since it belongs to the Spam
procedure which is no longer running. The result could be disastrous. (JavaScript has closures so it would keep the variable around even after Spam
exits, and Java and C++11 also have limited forms of this, but Ada doesn't have anything equivalent.) Therefore, Ada has rules to prevent this sort of thing from happening. To get around the rules, you can use 'Unrestricted_Access
(which is a GNAT attribute, not defined by the language), which tells the compiler "I know what I'm doing, don't worry about it".