tags:

views:

118

answers:

4

I'm trying to learn Ada for a course at the University, and I'm having a lot of problems wrapping my head around some of the ideas in it.

My current stumbling block: Let's say I have a function which takes a Matrix (just a 2-dimensional array of Integers), and returns a new, smaller matrix (strips out the first row and first column).

I declare the matrix and function like this:

type MATRIX is array(INTEGER range <>, INTEGER range <>) of INTEGER;
function RemoveFirstRowCol (InMatrix: in MATRIX) return MATRIX is

Then I decide on the size of the Matrix to return:

     Result_matrix: MATRIX (InMatrix'First(1) .. InMatrix'Length(1) - 1, InMatrix'First(2) .. InMatrix'Length(2) - 1);

Then I do the calculations and return the Result_matrix.

So here's my problem: when running this, I discovered that if I try to return the result of this function into anything that's not a Matrix declared with the exact proper size, I get an exception at runtime.

My question is, am I doing this right? It seems to me like I shouldn't have to know ahead of time what the function will return in terms of size. Even with a declared Matrix bigger than the one I get back, I still get an error. Then again, the whole idea of Ada is strong typing, so maybe this makes sense (I should know exactly the return type).

Anyways, am I doing this correctly, and is there really no way to use this function without knowing in advance the size of the returned matrix?

Thanks, Edan

A: 

The caller knows the dimensions of the matrix it passes to your function, so the caller can define the type of the variable it stores the function's return value in in terms of those dimensions. Does that really not work?

ndim
It does work, I just think it's a little awkward (since I don't want a caller to my function having to do these kinds of calculations).
Edan Maor
+1  A: 

your function cannot know the size of the result matrix in compile time you need to return a pointer to the new matrix :

type Matrix is array (Positive range <>, Positive range <>) of Integer; 
type Matrix_Ptr is access Matrix; 

       -- chop the 1'th row and column
       function Chopmatrix (
             Inputmatrix : in     Matrix ) 
         return Matrix_Ptr is 
          Returnmatrixptr : Matrix_Ptr;  

       begin

          -- create a new matrix with is one row and column smaller
          Returnmatrixptr  := new Matrix(2 .. Inputmatrix'Last, 2..  Inputmatrix'Last(2) );
          for Row in Inputmatrix'First+1 .. Inputmatrix'Last loop
             for Col in Inputmatrix'First+1 .. Inputmatrix'Last(2) loop
                Returnmatrixptr.All(Row,Col) :=   Inputmatrix(Row,Col);
             end loop;

          end loop;
          return Returnmatrixptr;
       end Chopmatrix ;
Alon
+2  A: 

You don't need to know the size of the returned matrix in advance, nor do you need to use an access (pointer) type. Just invoke your function in the declarative part of a unit or block and the bounds will be set automatically:

procedure Call_The_Matrix_Reduction_Function (Rows, Cols : Integer) is

   Source_Matrix : Matrix(1 .. Rows, 1 .. Cols);

begin
   -- Populate the source matrix

   -- ...

   declare
      Result : Matrix := RemoveFirstRowCol (Source_Matrix)
      -- Result matrix is automatically sized, can also be declared constant
      -- if appropriate.
   begin
      -- Process the result matrix

      -- ...

   end;
end Call_The_Matrix_Reduction_Function;

Caveat: Since the result matrix is being allocated on the stack, you could have a problem if the numbers of rows and columns are large.

Marc C
A: 

Because your MATRIX type is declared with unbound indexes, the type is incomplete. This means that it can be returned by a function. In this case, this acts as it were pointer. Of course the compiler does not know the exact indexes in compile time, the result matrix will always be allocated in heap.

Your solution should be working. The only problem is when you create the result matrix is, that it will work only if the original matrix index starts with 0.

m:MATRIX(11..15,11..20);

In this case m'first(1) is 11, m'length(1) is 5! So you get:

Result_matrix:MATRIX(11..4,11..9);

which is CONSTRAINT_ERROR...

Use the last attribute instead. Even if you usually use with 0 index.

But remember, you do not need to use pointer to the MATRIX because the MATRIX is also incomplete, and that's why it can be used to be returned by a function.

Krisztian