Ada Modeless Subprogram Parameters - ada

If a parameter in Ada is left modeless, what happens?
what is the difference between
procedure my_func ( param_1 : in param_type )
and
procedure my_func ( param_1 : param_type )
I am new to ada and have been writing most of my procedures as the latter. The program compiles and runs as expected.

There is no difference - if no parameter mode is given, the compiler assumes "in".
See http://www.ada-auth.org/standards/12rm/html/RM-6-1.html line beginning 18/3.
-- Martin

As suggested by Martin, the default mode is 'in' if not provided.
I would like to add that if possible, you can sometimes experiment with things about which you are doubtful.
like look at the below simple code, I have not given any mode to the arguement 'no_1'.
And as seen I am assigning value of 'no_2' to it.
with Ada.Text_IO; use Ada.Text_IO;
procedure just_testing is
procedure get_value (no_1 : Integer);
procedure get_value (no_1 : Integer) is
no_2 : Integer := 2;
begin
no_1 := no_2;
end get_value;
begin
Put("auto mode");
end just_testing;
And when I compile this code, look what we get as error.
>gnatmake just_testing.adb
gcc -c just_testing.adb
just_testing.adb:10:09: assignment to "in" mode parameter not allowed
gnatmake: "just_testing.adb" compilation error
So, compiler makes it clear that the default mode is 'in', as we can not assign any value to argument with mode in.

Related

Does Ada have any idiomatic rules on when to use a function versus a procedure with an output parameter?

You can assign to a variable by having a function return a value to it:
My_Int : Integer := My_Math_Func [(optional params)];
Or you can do it like this with a procedure (assuming My_Int has already been declared):
My_Math_Proc ([optional params;] [in] out My_Int);
Obviously a procedure can't initialize a variable like the function does in the first example, but I'm hoping for some concrete, practical rules on when and why to pick one over the other.
Two to get you started...
When more than one result is to be returned, a procedure with several OUT parameters is often a good choice.
When the size of the object is unknown prior to the subprogram call, an OUT parameter cannot be used because it would have to be declared precisely the right size, but a function return can set the size by initialising the variable in the caller. This is commonly used with a variable declared in a Declare block, which can hold a different sized string each time it is invoked.
This example shows the variable "text" initialised by calling a Read_File function, to hold the contents of a different file on each iteration of the loop. Safe, no "malloc" or "free" or pointers necessary. (Filename is an array of filenames in this example)
for i in 1 .. last_file loop
declare
text : String := Read_File(Filename(i));
-- the size of "text" is determined by the file contents
begin
-- process the text here.
for j in text'range loop
if text(j) = '*' then
...
end loop;
end
end loop;
Edit : And I suppose I'd better mention the underlying mathematical principle, since Ada is based more closely on mathematical logic than many other languages.
Functions and procedures are both subprograms, but for different purposes:
a function is an abstraction over an expression : like a mathematical operator (and an operator in Ada is just a function). Ideally, it provides a result from a number of operands and nothing else, leaving them unchanged and having no state and no side effects. This ideal is called a "pure function" (and applying "pragma pure" asks the compiler to check its purity) - similar restrictions apply in functional programming (FP) languages. Pure functions allow a whole bunch of optimisation (because reordering them doesn't change results). In practice Ada is not that strict, allowing impure functions too.
a procedure is an abstraction over a statement. It generally has some physical effect (such as changing state) since it doesn't deliver a result.
So the logical separation between expressions and statements is carried over into subprograms (abstractions) as the separation between functions and procedures.
And this is probably the best way to decide which to use.
Brian Drummond already answered your question directly, but I wanted to add some additional info: If your type has some sort of initializing procedure, in Ada2005/Ada2012 you can convert it to an initializing function using extended return syntax. It will even work for limited types.
Say you have a package with a type like this:
package Example is
type My_Type is limited private;
procedure Initialize(Self : in out My_Type; Value : Integer);
procedure Print(Self : My_Type);
private
type My_Type is limited record
Value : Integer := 0;
end record;
end Example;
package body Example is
procedure Initialize(Self : in out My_Type; Value : Integer) is
begin
Self.Value := Value;
end Initialize;
procedure Print(Self : My_Type) is
begin
Ada.Text_IO.Put_Line(Self.Value'Image);
end Print;
end Example;
You can then make your own initializing function out of that procedure doing something like this:
function Make_My_Type (Value : Integer) return Example.My_Type is
begin
return Result : Example.My_Type do
Example.Initialize(Result,Value);
end return;
end Make_My_Type;
and you can initialize variables easily using the procedure hidden in your function underneath:
procedure Test
Thing : Example.My_Type := Make_My_Type(21);
begin
Example.Print(Thing);
end Test;
This is different than just making a variable and returning it. You are not able to do that with a limited type, but with extended return syntax, you can do it for any type.
Here is some additional info for extended return statements as well.

Ada : custom type in range 1..var?

I'm a very beginner of Ada code. I use GPS from AdaCore.
I would create a variable sized by the user.
I write this :
-- My ada program --
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
procedure main is
wanted : Integer := 10;
type custom is range 0..wanted;
...
But something went wrong in line 8 :
Builder results
C:\Users\**********\Desktop\ada project\src\main.adb
8:26 "wanted" is not static constant or named number (RM 4.9(5))
8:26 non-static expression used for integer type bound
I really don't understand what this mean... Can someone help me ?
Variable wanted is not a constant, it may change its value during program execution, therefore this variable is not allowed to be used as range constraint when declaring new types. You may however make it constant by using constant keyword (Wanted : constant Integer := 10;). It should resolve your problem.
As said by Timur, wanted has to be constant in its scope. This allows you some nice things such as declaring a type inside a procedure. Look at this, it might be of interest :)
-- My ada program --
with Ada.Text_IO, Ada.Integer_Text_IO;
use Ada.Text_IO, Ada.Integer_Text_IO;
procedure Main is
procedure Test (Wanted : Integer) is
type custom is new Integer range 0..wanted;
begin
Put_Line("First value " & Custom'Image (Custom'First)
& " Last value " & Custom'Image (Custom'Last));
end Test;
begin
Test (10);
Test (12);
end Main;
Output is
First value 0 Last value 10
First value 0 Last value 12
In this case, your type is different from one call to another but it works as wanted is constant within the procedure. The only thing is that the type defined has to be a new derived type of the type of your parameter.
I let you think about the possibilities :)

raised CONSTRAINT_ERROR : polynom.adb:85 index check failed

I created an array like this one:
type coef_list is array(Integer range 0..50) of Integer;
But the message appears when I call this function:
t:= times(r,q); --that multiply two polynoms.
Why? I need a dynamic array? with Ada.Vectors but how to used it? if there is any simple example to guide me, please share? Thx
Ada procedures (and similar for functions) require this structure:
procedure Foo is
-- declarations goes here
begin
-- code goes here
end Foo;
In your code, both polynomials and Main is missing the begin.
You have also put declarations (value1 : integer := 1; etc) after begin in print_polynoms, which is illegal.
Other problems with your code:
You redefine the built-in type String.
The type zero is not defined anywhere.
The type String_Pointer is not defined anywhere.
This syntax makes no sense: type Polynom is new Integer(p,p1,p2,p3,p4,q,q1,q2); And the type Polynom is never used. Why declare it?
The variable zero is not defined anywhere.
Why have an inner procedure Main here? It does nothing anyway. And is never called. Probably better to move print_polynoms out of Main, as an inner function of polynomials directly.
The polynomials procedure does nothing, print_polynoms will never be called.
Also, the code you pasted seems to not be the same as the code you tried to compile. (main is not declared at line 9)

Inconsistent argument passing mode

Consider the following code (which compile with GCC 4.7.4):
procedure Main is
procedure Sub_Proc(N : in out Integer) is
M : Integer;
begin
M := N;
end;
procedure Proc(N : out Integer) is
begin
Sub_Proc(N);
end;
N : Integer;
begin
Proc(N);
end Main;
The procedure Proc is supposed to ensure that the argument N which is an out argument will never be read inside his body. But it passes this argument to a procedure Sub_Proc which takes an in out argument, so potentially the previous argument will be read inside this procedure whereas the calling procedure ensured the opposite.
Is it a GCC bug or an Ada standard specificity ?
You’ll have received a warning on the Sub_Proc(N); call: "N" may be referenced before it has a value. So the compiler was trying to help!
In Ada 83, your program would have been illegal: 6.4.1(3) says "for the mode in out, the variable must not be a formal parameter of mode out”. Indeed, using -gnat83, and after a minor rearrangement of the code to allow it to compile, the equivalent to the above warning is the error (Ada 83) illegal reading of out parameter.
In Ada 95 and Ada 2012 it is OK to read the value of an out parameter after it has been assigned; in ARM95 6.4.1(15) we find that the value starts out uninitialized (as indicated by the warning message noted above), so using it is a Bad Idea.
So the answer is, GNAT’s behaviour conforms with the standard.

The use of IN OUT in Ada

Given below is some code in ada
with TYPE_VECT_B; use TYPE_VECT_B;
Package TEST01 is
procedure TEST01
( In_State : IN VECT_B ;
Out_State : IN OUT VECT_B );
function TEST02
( In_State : IN VECT_B ) return Boolean ;
end TEST01;
The TYPE_VECT_B package specification and body is also defined below
Package TYPE_VECT_B is
type VECT_B is array (INTEGER range <>) OF BOOLEAN ;
rounded_data : float ;
count : integer ;
trace : integer ;
end TYPE_VECT_B;
Package BODY TYPE_VECT_B is
begin
null;
end TYPE_VECT_B;
What does the variable In_State and Out_State actually mean? I think In_State means input variable. I just get confused to what actually Out_State means?
An in parameter can be read but not written by the subprogram. in is the default. Prior to Ada 2012, functions were only allowed to have in parameters. The actual parameter is an expression.
An out parameter implies that the previous value is of no interest. The subprogram is expected to write to the parameter. After writing to the parameter, the subprogram can read back what it has written. On exit the actual parameter receives the value written to it (there are complications in this area!). The actual parameter must be a variable.
An in out parameter is like an out parameter except that the previous value is of interest and can be read by the subprogram before assignment. For example,
procedure Add (V : Integer; To : in out Integer; Limited_To : Integer)
is
begin
-- Check that the result wont be too large. This involves reading
-- the initial value of the 'in out' parameter To, which would be
-- wrong if To was a mere 'out' parameter (it would be
-- uninitialized).
if To + V > Limited_To then
To := Limited_To;
else
To := To + V;
end if;
end Add;
Basically, every parameter to a function or procedure has a direction to it. The options are in, out, in out (both), or access. If you don't see one of those, then it defaults to in.
in means data can go into the subroutine from the caller (via the parameter). You are allowed to read from in parameters inside the routine. out means data can come out of the routine that way, and thus you are allowed to assign values to the parameter inside the routine. In general, how the compiler accomplishes the data passing is up to the compiler, which is in accord with Ada's general philosophy of allowing you to specify what you want done, not how you want it done.
access is a special case, and is roughly like putting a "*" in your parameter definition in Cish languages.
The next question folks usually have is "if I pass something large as an in parameter, is it going to push all that data on the stack or something?" The answer is "no", unless your compiler writers are unconsionably stupid. Every Ada compiler I know of under the hood passes objects larger than fit in a machine register by reference. It is the compiler, not the details of your parameter passing mechanisim, that enforces not writing data back out of the routine. Again, you tell Ada what you want done, it figures out the most efficient way to do it.

Resources