The closest thing Ada has to pointers are called access types. These access types are really cleverly designed. Someone wrote that “in Ada it is syntactically invalid to leak pointers to memory that is about to become invalid.” That’s a C programmer’s wet dream. That’s the kind of power you can get when you pay great minds a lot of money to solve hard problems.

There are several rules surrounding access types to make this work and I’m not going to give a comprehensive guide, but these are the basics: To reference an object, you have to create an access type for that type of object, and then declare a variable of that access type. This shouldn’t be particularly surprising. Assming we have a boat:

In[4]:

type Boat is record Captain : Person; Propulsion : Sails_Or_Motor; end record; My_Boat : aliased Boat := (Captain => Me, Propulsion => Sails);

The aliased indicator is required in order to get a reference from a variable in the first place.15 The reason for this is elementary: in order to get the address of an object, the object must have an address. In order to have an address, the object must reside in primary memory. The compiler tries its very hardest to avoid storing objects in primary memory, because that is slow compared to storing them in cpu registers – or even optimising them away entirely. If we want the compiler to not do this, we make it an aliased declaration, which guarantees it will have a memory address. We can then let others access our boat by creating

In[5]:

type Boat_Access is access Boat; Family_Key : Boat_Access := My_Boat'Access;

This creates an access called Family_Key which, well, accesses my boat. Anyone who gets hold of the Family_Key value can do stuff to my boat, including replace me as the captain.

But! Big but.16 And I cannot lie. While access types are free to reference any global object, they can only reference a stack object if the stack object is declared in the same scope as the access type itself. In addition, two different types declared to be access Boat are actually incompatible. If you want to copy a reference, you have to use the same access type that was originally used to create the reference. That way, references can only ever point to live stack objects.17 This is a tricky part of Ada when you are learning it. Despite what masochists say, memory management is hard. In C, you get weird security flaws. In Ada, you have to really fight to get the compiler to accept your code. If you are struggling with learning this, my recommendation is to try different ways to intentionally create a pointer to invalid memory. You’ll know exactly what the problem is, and then the Ada compiler will complain – and bam! – you now have an understanding for exactly what the compiler complains about when it gives you that error message.

We can also create access types that serve as read-only views of the object they reference, limit access types to never contain null (i.e. always reference some object), create access types that can only reference objects allocated a certain way, or limit the total amount of memory available for an access type, or …

In our case, we parametrise the Row type on an access to the source string:

In[6]:

type Row (Source : not null access constant String; Columns : Positive) is tagged private;

The Source parameter accepts any non-null read-only access-to-string type. Then when we create objects of this type, the actual reference we pass in comes from a string read from the input file:

In[7]:

Raw : aliased constant String := Get_Line (Input.File); Header : constant CSV.Row := CSV.Parse (Raw'Access);