I'm trying to create a package of generic adjacency matrices to define graphs, and the first goal is to define a static version based on two-dimensional array:
with Ada.Containers.Vectors; generic type Weight_Type is private; with function "=" (Left, Right : Weight_Type) return Boolean; No_Edge_Value : Weight_Type; package Generic_Adjacency_Matrices is type Static_Adjacency_Matrix is array (Positive range <>, Positive range <>) of Weight_Type; function Create (Vertices : Positive) return Static_Adjacency_Matrix; end Generic_Adjacency_Matrices; package body Generic_Adjacency_Matrices is function Create (Vertices : Positive) return Static_Adjacency_Matrix is AM : Static_Adjacency_Matrix (1 .. Vertices, 1 .. Vertices); begin for I in AM'Range(1) loop for J in AM'Range(2) loop AM(I, J) := No_Edge_Value; end loop; end loop; return AM; end Create; end Generic_Adjacency_Matrices; To make sure that the matrix is square, I've tried using Static_Predicate to assert the range of both dimensions is the same.
Reference manual notes (3.2.4 NOTE 2) "A Static_Predicate, like a constraint, always remains True for all objects of the subtype, except in the case of uninitialized variables and other invalid values. A Dynamic_Predicate, on the other hand, is checked as specified above, but can become False at other times. For example, the predicate of a record subtype is not checked when a subcomponent is modified."
So, in my opinion, it makes more sense to use Static_Predicate, because matrix has fixed constraints determined at declaration.
with Ada.Containers.Vectors; generic type Weight_Type is private; with function "=" (Left, Right : Weight_Type) return Boolean; No_Edge_Value : Weight_Type; package Generic_Adjacency_Matrices is type Static_Adjacency_Matrix is array (Positive range <>, Positive range <>) of Weight_Type with Static_Predicate => Static_Adjacency_Matrix'First(1) = Static_Adjacency_Matrix'First(2) and Static_Adjacency_Matrix'Last(1) = Static_Adjacency_Matrix'Last(2); function Create (Vertices : Positive) return Static_Adjacency_Matrix; end Generic_Adjacency_Matrices; Unfortunately, it's illegal in Ada: Static_Predicate can't be defined with 'Range, 'First, and 'Last.
Although, Dynamic_Predicate can be defined in such a way, I'd like to know other, better suited approaches.
For a example, the type Adjacency_Matrix can be declared private so the function Create, which produces square matrices, is mandatory to use. I don't like this approach, because I don't see why this type should be private at all, and it requires me to define access procedures.