Reputation: 603
I have the following spec:
generic
type Value_Type is private;
package Containers.Arrays is
type Static_Array is array(Positive range <>) of Value_Type;
type Static_Array_Access is access all Static_Array;
type Dynamic_Array is tagged private;
function Length(Self : Dynamic_Array) return Natural with Inline;
function "&"(Left : Dynamic_Array; Right : Value_Type) return Dynamic_Array;
private
type Dynamic_Array is tagged record
Backing : Static_Array_Access;
end record with
Variable_Indexing => Variable_Indexer;
type Variable_Reference(Data : access Value_Type) is null record with
Implicit_Dereference => Data;
function Variable_Indexer(Self : Dynamic_Array; Index : Positive)
return Variable_Reference with Pre => Index <= Self.Length;
Along with an implementation of Variable_Indexer as follows:
function Variable_Indexer(Self : Dynamic_Array; Index : Positive)
return Variable_Reference is
begin
return Variable_Reference(Data => new Value_Type'(Self.Backing(Index)));
end Variable_Indexer;
I know the problem here already, but I'll still give my test code and explain what happens.
DA : Dynamic_Array := 'a' & 'b' & 'c';
pragma Assert(DA.Length = 3);
pragma Assert(DA(1) = 'a');
pragma Assert(DA(2) = 'b');
pragma Assert(DA(3) = 'c');
All good so far
DA(1) := 'A'; --Change to majiscule from miniscule
pragma Assert(DA(1) = 'A'); --fails
I know this is because Variable_Indexer didn't reference DA(1), but actually allocated a new variable on the heap with the value that DA(1) just so happened to have. I figure I need to alias the value and return an access to the alias. I, however, have been unable to get such a thing to compile, let alone work.
Upvotes: 1
Views: 319
Reputation: 603
Thanks to @ajb for this one, as I completely forgot about aliasing the elements of an array.
Change Static_Array to:
type Static_Array is array(Positive range <>) of aliased Value_Type;
and change Variable_Indexer to:
function Variable_Indexer(Self : Dynamic_Array; Indexer : Positive) return Variable_Reference is
begin
return Variable_Reference'(Data => Self.Backing(Index)'Access);
end Variable_Indexer;
Now, instead of creating a new value on the heap, and returning a pointer to that, it now returns a pointer to the element in the array; this is proper behavior.
Upvotes: 3