[ Table of Contents ]
We continue our discussion of access types, and provide an example illustrating the use of general access types. First, we discuss dereferencing with the reserved word all, which pertains to both pool-specific and general access types. Then we discuss two other features of the language, which pertain only to general access types.
Dereferencing
Suppose we had declared a record type, My_Rec_Type, with two integer components, Comp1 and Comp2, and then declared an access type, Rec_Ptr_Type, whose values point to values of My_Rec_Type. Now, we can write, in an executable part:
P1:= new My_Rec_Type'(2,4); -- dynamic allocation and initialization P2:= new My_Rec_Type'(6,8); -- dynamic allocation and initialization P1.Comp1 := 5; -- change 1st component of 1st object P1.Comp2 := 10; -- change 2nd component of 1st object P2.all := (20,30); -- change (6,8) to (20,30) in 2nd object P1 := P2; -- now P1 also points to (20,30) object |
Whereas the name P2 designates or "references" an unnamed record object, the expression P2.Comp1 designates a component of the object and the expression P2.all designates the whole object -- a dereferencing operation.
Aliased Objects and the Access Attribute
A declared object can be pointed to by an access value only if it is originally declared as an aliased object -- one that can have multiple names. Now suppose we wrote, in a block that can "see" My_Rec_Type:
declare GAT_Rec_Ptr is access all My_Rec_Type; -- general access type PA, PB, PC : GAT_Rec_Ptr; -- 3 general access values RecA, RecB : aliased My_Rec_Type; -- 2 aliased objects begin RecA := (15,7); RecB := ( 3,9); PA := RecA'Access; -- points to RecA PB := RecB'Access; -- points to RecB PB.Comp2 := PA.Comp1; -- RecB now (3,15) PC := PA; -- points to RecA (15,7) PA.all := PB.all; -- RecA now (3,15) PB.all := PC.all; -- RecB now (15,7) end; |
RecA and PA.all are two names (aliases) for the same object, and RecB and PB.all are two names (aliases) for another object. PC.all is another name, which can represent either RecA or RecB. Note the use of the 'Access attribute, not to be confused with the reserved word access.
Lifetime Rule for Access Types
There is a lifetime rule that says: given an access type T, X'Access yielding a result of type T is allowed only if X can live at least as long as T. This rule prevents the potential for dangling references.
Example Program Illustrating General Assess Types
Our example involves a callback situation in which a look-up table is used to get access values that select appropriate response procedures and parameters, such as the response to a button click or other event. (The events are simulated here with keyboard inputs.) We are using a technique described in Section 9.3 of [Ben-Ari98], but applied to a different situation.
The types declared in this main procedure include two general access types
-- Message_Ptr, pointing to aliased constant strings -- and Procedure_Ptr, pointing to
procedures having identical profiles. One procedure represents the response to the pushing of a button (up or down). The other represents the response to other events, such as an elevator arriving at a floor. A look-up table named Callback holds pairs of access values -- one of each access type. |
In this example the event responses are simply to display one-line messages indicating that those events have occurred.
Source Code Listing
---------------------------------------------------------- ----------------- Test_General_Accesses ------------------ -- This interactive program employs single keystrokes to -- represent two classes of events. Lower case 'u' and -- 'd' represent a person pushing an up or down button. -- Upper case 'U' and 'D' represent the arrival of an -- up-going or down-going elevator, respectively. General -- access types are used to reference appropriate -- responses and display messages. A 'Q' input is used to -- quit the program. ---------------------------------------------------------- with Ada.Text_IO; use Ada.Text_IO; procedure Test_General_Accesses is -- types (1 enumeration, 2 general access, 1 record) type Inputs is (Up, Down, Stop_Up, Stop_Down); -- 2 button events -- & 2 other events type Message_Ptr is access constant String; type Procedure_Ptr is access procedure(I : in Inputs; S : in String); type Callbacks is record Message : Message_Ptr; Action : Procedure_Ptr; end record; -- aliased objects (constant) Msg_Up : aliased constant String := "the up light is on."; Msg_Down : aliased constant String := "the down light is on."; Msg_Stop_Up : aliased constant String := "the up light is off."; Msg_Stop_Dn : aliased constant String := "the down light is off."; -- procedures (2 with same parameter profile) -------------------------------------------------- procedure Respond_To_Button(I : in Inputs; S : in String) is begin Put_Line("A traveler pushed a button and " & S); end Respond_To_Button; -------------------------------------------------- procedure Respond_To_Event(I : in Inputs; S : in String) is begin Put_Line("The elevator arrived and " & S); end Respond_To_Event; -------------------------------------------------- -- look-up table for pairs of access values Callback : constant array (Inputs) of Callbacks := ((Msg_Up'Access, Respond_To_Button'Access), (Msg_Down'Access, Respond_To_Button'Access), (Msg_Stop_Up'Access, Respond_To_Event'Access) , (Msg_Stop_Dn'Access, Respond_To_Event'Access)); Key : Character; -- keyboard input Valid_Input : Boolean; Inp : Inputs := Stop_up; -- button or event inputs begin Put_Line("Enter u, d, U, D or Q"); loop Valid_Input := True; Put(">>"); Get(Key); case Key is -- translate to button or event when 'u' => Inp := Up; when 'd' => Inp := Down; when 'U' => Inp := Stop_Up; when 'D' => Inp := Stop_Down; when 'Q' => Put_Line("Goodbye"); exit; when others => Valid_Input := False; Put_Line("Invalid input, try again."); end case; if Valid_Input then Callback(Inp).Action(Inp, Callback(Inp).Message.all); -- Note dereferencing (Message.all) to obtain string -- as second parameter of procedure call to Action. -- Action turns out to be either Respond_To_Button -- or Respond_To_Event. end if; end loop; end Test_General_Accesses; ----------------------------------------------------------- |
Here is a sample output from the above program:
Enter u, d, U, D or Q >>u A traveler pushed a button and the up light is on. >>d A traveler pushed a button and the down light is on. >>d A traveler pushed a button and the down light is on. >>D The elevator arrived and the down light is off. >>U The elevator arrived and the up light is off. >>y Invalid input, try again. >>u A traveler pushed a button and the up light is on. >>Q Goodbye |
Related Topics
[ Back to top of page ]