I have a problem in Ada concurrent programming. I have to write a simple program in Ada that creates N of tasks of the same type, where N is the input from keyboard. The problem is that I have to know N before compilation...
I have tried to declare a separate type:
TYPE my_arr IS ARRAY(INTEGER RANGE <>) OF some_task;
and later in BEGIN section of main procedure:
DECLARE arr: my_arr(1 .. N);
but I get the error
unconstrained element type in array declaration
Which (I think) means that task type some_task is of unknown size.
Can anyone please help ?
This is a rewrite of the original answer, now that we know that the task type in
question is discriminated.
You are passing a value to each task via a 'discriminant' without a default, which makes the task type unconstrained; you can't declare an object of the type without supplying a value for the discriminant (and supplying a default wouldn't help, because once the object has been created the discriminant can't be changed).
One common approach to this uses access types:
with Ada.Integer_Text_IO;
with Ada.Text_IO;
procedure Maciek is
task type T (Param : Integer);
type T_P is access T;
type My_Arr is array (Integer range <>) of T_P;
task body T is
begin
Ada.Text_IO.Put_Line ("t" & Param'Img);
end T;
N, M : Integer;
begin
Ada.Text_IO.Put ("number of tasks: ");
Ada.Integer_Text_IO.Get (N);
Ada.Text_IO.Put ("parameter: ");
Ada.Integer_Text_IO.Get (M);
declare
-- Create an array of the required size and populate it with
-- newly allocated T's, each constrained by the input
-- parameter.
Arr : My_Arr (1 .. N) := (others => new T (Param => M));
begin
null;
end;
end Maciek;
You may need to deallocate the newed tasks once they are completed; in the code above, the tasks' memory is leaked on exit from the declare block.
Allocate them in a 'declare block', or dynamically allocate them:
type My_Arr is array (Integer range <>) of Some_Task;
type My_Arr_Ptr is access My_Arr;
Arr : My_Arr_Ptr;
begin
-- Get the value of N
-- Dynamic allocation
Arr := new My_Arr(1 .. N);
declare
Arr_On_Stack : My_Arr(1 .. N);
begin
-- Do stuff
end;
end;
If you are sure at runtime, how many tasks you want, you can pass that as command-line argument.
with Ada.Text_IO; use ADA.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
with Ada.Command_Line;
with Ada.Strings;
procedure multiple_task is
No_of_tasks : Integer := Integer'Value(Ada.Command_Line.Argument(1));
task type Simple_tasks;
task body Simple_tasks is
begin
Put_Line("I'm a simple task");
end Simple_tasks;
type task_array is array (Integer range <>) of Simple_tasks;
Array_1 : task_array(1 .. No_of_tasks);
begin
null;
end multiple_task;
And run as
> multiple_task.exe 3
I'm a simple task
I'm a simple task
I'm a simple task
Related
Please solve this in ADA:
--initialize first array (My_Array) with random binary values
procedure Init_Array (Arr : BINARY_ARRAY) is
package Random_Bit is new Ada.Numerics.Discrete_Random (BINARY_NUMBER);
use Random_Bit;
G : Generator;
begin
Reset (G);
for Index in 1..16 loop
Arr(Index) := Random(G);
end loop;
end Init_Array;
--reverse binary array
procedure Reverse_Bin_Arr (Arr : BINARY_ARRAY) is
hold : BINARY_ARRAY := Arr;
begin
for Index in 1..16 loop
Arr(15 - Index) := hold(Index);
end loop;
end Reverse_Bin_Arr;
--initialize first array (My_Array) with random binary values
procedure Init_Array (Arr: in out BINARY_ARRAY);
--reverse binary array
procedure Reverse_Bin_Arr (Arr : in out BINARY_ARRAY);
I believe my above procedures are correct. I just keep getting the following error:
assgn.adb:7:15: not fully conformant with declaration at assgn.ads:7
assgn.adb:7:15: mode of "Arr" does not match
assgn.adb:19:15: not fully conformant with declaration at assgn.ads:10
assgn.adb:19:15: mode of "Arr" does not match
gnatmake: "assgn.adb" compilation error
The first procedure should initialize a random array that houses each bit of a binary number. Example: [1,0,1,0,1,1,1,1,0,0,0,1,1,0,1,0]
The second procedure should reverse the bits in the binary array.
The error not fully conformant with declaration means exactly what it says; there's a mismatch between the spec and the implementation
The specification says (notice the in out parameter mode):
procedure Init_Array (Arr: in out BINARY_ARRAY);
but the implementation defaults to in:
procedure Init_Array (Arr : BINARY_ARRAY) is
If I have defined an array type like
type Integer_Array is array(Natural range <>) of Integer;
and also use package Ada.Containers.Vectors as
package Integer_Vectors is new Ada.Containers.Vectors(
Element_Type => Integer,
Index_Type => Natural);
use Integer_Vectors;
How can I implement the following function?
function To_Integer_Array(V : Integer_Vectors.Vector) return Integer_Array;
What I have so far
Conceptually, it seems really easy:
Declare Temp_Arr as Integer_Array with capacity of V.Length
Iterate over V and copy all elements to Temp_Arr
Return Temp_Arr
Step 1. is giving me headaches though. I have tried:
function To_Integer_Array(V: Integer_Vectors.Vector) return Integer_Array is
Temp_Arr: Integer_Array(1..V.Length);
begin
-- Todo: copy values here
return Temp_Arr;
end To_Integer_Array;
This will throw
expected type "Standard.Integer"
found type "Ada.Containers.Count_Type"
While the error absolutely makes sense, I am unsure as to how I might solve it.
Is there a way to cast Ada.Containers.Count_Type to Standard.Integer?
Would there be another way to create an Integer_Array from Integer_Vector?
Thanks to Brian the declaration now works. The correct implementation for my function looks like this:
function To_Integer_Array(V: Integer_Vector) return Integer_Array is
Temp_Arr: Integer_Array(1..Natural(V.Length));
begin
for I in Temp_Arr'Range loop
Temp_Arr(I) := V.Element(I);
end loop;
return Temp_Arr;
end To_Integer_Array;
I need to create a number of functions that deal with matrices of arbitrary size. I am familiar with the declare syntax used here, but this is for an university assignment, and my professor told me that using 'declare' there is overkill. I can't find anything relevant online, any help?
Basically I'm looking to get the matrix size via keyboard and then work with the resulting matrix, I'm stuck with the declare
Currently I have:
type myMatrix is array (Natural range <>, Natural range <>) of Integer;
type myVector is array (Natural range <>) of Integer;
And I use it as:
procedure Lab1 is
begin
declare A, B: myVector(1..5):=
(3, 14, 15, 92, 6);
which doesn't allow to specify the size at runtime, and as:
declare
int1:Integer:=generate_random_number(50)+2;
int3:Integer:=generate_random_number(50)+2; -- +2 so we don't get length/size 0 or 1
X, Y:myVector(1..int1):=(others=>generate_random_number(20));
MT:myMatrix(1..int1, 1..int3):=(others =>(others=>generate_random_number(10))); -- 'others' used for all the unmentioned elements, http://rosettacode.org/wiki/Array_Initialization
MS:myMatrix(1..int3, 1..int1):=(others =>(others=>generate_random_number(10)));
F3_result:myMatrix(1..int1, 1..int1);
begin
F3_result:=F3(X, Y, MT, MS);
end;
which uses a declare block. I might need to use the resulting array later on, and as I understand here F3 is a local variable, and therefore can't be reused?
Are there any other ways?
I agree with your teacher that putting a declare just after a begin will in general show that the declare block is unneeded (the only exception I can think of is because you want to handle exceptions that might arise as part of the declaration of the variables within the enclosing subprogram).
So you can just remove both begin and declare at the start of your subprogram, and that should work the same.
I'm trying populate a multidimensional array on PostgreSQL, but it not work. Below my code:
CREATE OR REPLACE FUNCTION teste()
RETURNS void AS
$BODY$
DECLARE
tarifas NUMERIC[7][24];
a INTEGER;
b INTEGER;
BEGIN
FOR a IN 0..6 LOOP
RAISE NOTICE 'TESTE TESTE %', a;
FOR b IN 0..23 LOOP
RAISE NOTICE 'tarifas[%][%] = 0;', a, b;
tarifas[a][b] = 0;
END LOOP;
END LOOP;
END
$BODY$
LANGUAGE plpgsql VOLATILE;
Postgres has a dedicated function for that purpose exactly: array_fill():
returns an array initialized with supplied value and dimensions,
optionally with lower bounds other than 1
Use it:
CREATE OR REPLACE FUNCTION teste()
RETURNS void AS
$func$
DECLARE
tarifas numeric[7][24] := array_fill(0, ARRAY[7,24]);
a int;
b int;
BEGIN
-- do something
END
$func$ LANGUAGE plpgsql;
Notes
Array dimensions in numeric[7][24] are just documentation. The manual:
The current implementation does not enforce the declared number of
dimensions either. Arrays of a particular element type are all
considered to be of the same type, regardless of size or number of
dimensions. So, declaring the array size or number of dimensions in
CREATE TABLE is simply documentation; it does not affect run-time behavior.
About the assignment operator in plpgsql: := or =:
The forgotten assignment operator "=" and the commonplace ":="
It's generally not possible to write to an array element directly. You can concatenate or append / prepend elements. Or assign an array as a whole. Details in the manual. But a statement like this is not possible:
tarifas[%][%] = 0
Default lower bound of an array is 1, not 0. But you can define arbitrary array dimension. Example:
SELECT '[2:3][2:4]={{7,7,7},{7,7,7}}'::int[]
I am trying to use the 'Last attribute with a 2D array in Ada, but I can't seem to find the correct syntax to do so.
I know that if I have a 1D array/vector I can use A'last or A'last(n) where n is the nth dimension. But if I do the following
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
end temp;
I get the following compile time error:
Storage_Error stack overflow (or erroneous memory access)
So what am I doing wrong?
I am using GNAT Pro 6.4.1 on Linux.
I'd be very surprised if you got a compile-time Storage_Error on that code.
I've grabbed a copy of your code and modified it as follows; it compiles without error using GNAT (gcc-4.4):
procedure Array_2D is
type UnconstrainedArray_2D is array (Integer range <>, Integer range <>) of Integer;
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
for i in 0..tempTable'last(1) loop
for j in 0..tempTable'last(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
return 42; -- added this
end temp;
begin
null;
end Array_2D;
(Note that I had to add the missing return statement in temp.)
Your syntax for the 'Last attribute (not "command") is correct, but since Ada arrays can have arbitrary lower and upper bounds, it's better to use the 'Range attribute instead:
for i in tempTable'Range(1) loop
for j in tempTable'Range(2) loop
tempTable(i, j) := Table(i,j);
end loop;
end loop;
As for the Storage_Error exception, that could easily happen at run time (not compile time) if you call your temp function with a very large value for tempIn. Remember that it has to allocate enough space to hold tempIn**2 Integer objects. Presumably you've also created another UnconstrainedArray_2D object to be passed in as the Table parameter.
It's conceivable that the compiler itself could die with a Storage_Error exception, but I don't see anything in your code that might cause that.
Show us a complete (but small) program that demonstrates the problem you're having, along with the exact (copy-and-pasted) error message. Please distinguish clearly between compile-time and run-time errors.
Your tempTable might have a range of 0..tempIn, but you don't know what range your Table has.. They could be of different length, too.
You would have to check that the length is the same and then use relative indices, like this:
function temp(tempIn : in Integer;
Table : in UnconstrainedArray_2D) return Integer is
tempTable : UnconstrainedArray_2D(0..tempIn, 0..tempIn);
begin
if tempTable'Length (1) /= Table'Length (1) or else
tempTable'Length (2) /= Table'Length (2)
then
raise Constraint_Error; -- or something else
end if;
for i in 0 .. tempTable'Length (1) - 1 loop
for j in 0 .. tempTable'Length (2) - 1 loop
tempTable(tempTable'First (1) + i, tempTable'First (2) + j) :=
Table(Table'First (1) + i, Table'First (2) + j);
end loop;
end loop;
end temp;
that way it is ensured that both tables are same length and all indices are valid.
If your tempTable is allowed to be smaller than Table, simply adjust the length check to >. The indices would still be valid.
I don't see an actual value for tempIn set. If the value for tempIn coming into the function temp has not been properly initialized or explicitly set, then the value in tempIn could be anything and probably not something you would like.
I was thinking of a default value. (probably shouldn't post when I am not feeling well :-)