I have a private type that internally uses a 2 dimensional array, while doing additional processing whenever the elements of that array are set. My package looks something like this:
with MyElements;
generic
Width, Height : Positive;
package MyPackage is
subtype MyXCoordinate is Positive range 1..Width;
subtype MyYCoordinate is Positive range 1..height;
type MyCoordinate is
record
x : MyXCoordinate;
y : MyYCoordinate;
end record;
type MyType is private;
function Create return MyType;
function Get (this : in MyType;
coord : in MyCoordinate) return MyElements.MyElementType;
procedure Set (this : out MyType;
coord : in MyCoordinate;
element : in MyElements.MyElementType);
private
type MyTypeData is array (MyXCoordinate,MyYCoordinate)
of MyElements.MyElementType;
type MyType is
record
data : MyTypeData;
otherstuff : ThatIsActuallyInThePackageButNotRelevant;
end record;
end MyPackage
However this forces packages that interface with MyPackage to either be generic, or to dynamically instantiate a new MyPackage with the correct parameters. Granted in execution these parameters are available fairly early (they are read from a file which is passed in on command line), but it still seems like I'm missing a language element that would do this for me.
I considered just using unbound Positives for the coordinates, removing the generic and allowing a run-time outofbounds error to be generated if the bounds fail, but I can't help feeling like Ada must have some way to do this cleanly at compile time.
I know I could use SPARK, but its overkill for this project (this project is a game, written in Ada to showcase its qualities) and somewhat defeats its purpose (showcasing Ada's compile-time error checking!).
Is my generic instantiation solution the correct way to handle this, or is there something better?
My attempts so far, that don't work but feel like they might be close-ish:
type MyType is
record
Width,Height : Positive;
subtype XCoordinate is Positive 1..Width;
subtype YCoordinate is Positive 1..Height;
data : array (XCoordinate,YCoordinate) of MyElements.MyElementType;
end record;
And wrapping the generic package with a 'generator' package that takes width/height as parameters to functions and procedures that then call-through to the package. (lots of code, doesn't work, wont waste space here with it).