I am unable to figure out keyword separate in Ada and its depth concept. Please help me to understand by giving a small example?
Lets say I have a nested procedure
with ada.text_io; use ada.text_io;
procedure main is
procedure proc is
begin
put_line ("i am proc");
end proc;
begin
put_line ("main");
end main;
How to use separate keyword ?
You primarily use the separate keyword to achieve one of 2 effects.
OS specific actions. (Put 2 versions of the procedure / functions in different directories, and compile for 2 different targets)
Separation of a lengthy procedure from surrounding code.
Here is an example to show the syntax.
package_x.ads
package Package_X is
procedure Foo;
procedure Sep;
end Package_X;
package_x.adb
package body Package_X is
procedure Foo is
begin
null;
end Foo;
procedure Sep is separate;
end Package_X;
package_x-sep.adb
separate (Package_X) procedure Sep is
begin
null;
end Sep;
The separate keyword creates a unit of compilation, a subunit, that is compiled independently. The parameter of separate refers to the package in which the subunit is a sub unit of.
So if you had a package body X, then you remove procedure Y from it, you create a sub unit of X by creating a new file in which you place Y, and put "separate(X)" at the start of the file, to indicate that Y is really part of X.
Related
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.
I want to create a procedure without parameters (In SQL DEVELOPER) but I am not sure how to do it, I have tried it in the following way and it sends me an error in "Num1 NUMBER";
create or replace package PK_MAC as
PROCEDURE PR_PRUEBAS
IS
Num1 NUMBER;
BEGIN
Num1 := 2;
end;
end;
You're trying to create a procedure or a package, with a procedure?
Here is a working example of what you're doing, as a package.
Your package will have two parts, a SPEC and a BODY.
The SPEC will publicly share the definition of the procedure and the variable, NUM1.
The BODY will define what the procedure actually does. Since NUM1 is defined already in the context of the package in the spec, I can use it in my procedure in the body.
create or replace package PK_MAC as
num1 integer;
PROCEDURE PR_PRUEBAS;
end;
/
create or replace package body PK_MAC IS
procedure pr_pruebas is
BEGIN
Num1 := 2;
end pr_pruebas;
end PK_MAC;
/
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 :)
I have to learn Ada so I can write an interpreter for it. But I cannot find many resources on learning the language. I get the above message when attempting to compile the following code: I save the file as check_positive.adb. What else am I supposed to do? I ran gnatls Check_Positive.adb after I ran gnatchop -w Check_Positive.adb. I am using GNAT Community v5.1.0.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure Check_Positive is
N : Integer;
begin
Put ("Enter an integer value: "); -- Put a String
Get (N); -- Read in an integer value
if N > 0 then
Put (N); -- Put an Integer
Put_Line (" is a positive number");
end if;
end Check_Positive;
gnatls and gnatchop will not compile your code, you should try gnatmake:
gnatmake check_positive.adb
be aware that GNAT expects lower-case filenames and one procedure/function/package spec/package body per file. If you organize your code that way, you won't need gnatchop.
Question: why and how to fix this error message about ADA? Thax
12:04 declarations must come before "begin"
29:01 statement expected
With Ada.Text_IO; Use Ada.Text_IO;
With Ada.Integer_Text_IO; Use Ada.Integer_Text_IO;
With Ada.Strings.Unbounded; Use Ada.Strings.Unbounded;
With Ada.Strings.Bounded;
procedure polynomial is
begin
function evaluate (x: Integer) return Integer is
type i is new Integer;
type p is new Integer;
type x is new Integer;
begin
for i in reverse 0..10 loop
i:= i-1;
p:= coef(i)+x*p;
end loop;
return p;
end evaluate;
end polynomial;
As the error message says, declarations must come before begin. Thus, if you have a declaration, it must come before the begin of the construct that encloses it. For example, the type declarations of i, x, and p (which should not be type declarations, but that's another problem) are directly enclosed in the evaluate function. Therefore, they must appear before the begin of the evaluate function, as they are.
The thing is that this applies to function and procedure declarations, too--and a complete function body, such as evaluate, counts as a declaration for this rule. evaluate is directly enclosed in polynomial. Therefore, it must appear before the begin line belonging to polynomial, whereas your code puts it right after the begin line, which is illegal.
There are actually two ways to fix it: (1) Move evaluate before the begin line. (2) Add a block that begins with declare:
procedure polynomial is
begin
declare
function evaluate (x: Integer) return Integer is
i : Integer;
-- etc.
begin
-- etc.
end evaluate;
begin -- this is the BEGIN line of the block
-- Now put some code here!
end; -- this is the end of the block
end polynomial;
Now the evaluate function is directly enclosed in the block, not in polynomial, and it must occur before the begin line of the block, but it doesn't have to occur before the begin line of polynomial.
A couple other things: This declaration:
type i is new Integer;
does not mean that "the type of i is an integer". It means you're declaring a new type named i. You don't want that, you want a variable.
i : Integer;
Second: note the part of the block where I said "now put some code here". That's necessary. Declaring the function evaluate does not run the function. You have to put in a statement that calls it, if you ever want your function to run. Your original incorrect code didn't have any statements that called evaluate, which is why I am not sure whether you understood that concept.