2. Program Unit: Procedures and Functions - JulTob/Ada GitHub Wiki

🧞‍♀️ Program Unit

The core of programming is very similar to doing Magic. 🧙 And I mean Harry Potter's Magic, not card tricks.

A program is pretty much as a spell. You say (sorry, write) the right words and... 🌫 Puff 🌫 Stuff happens.

🧞‍♀️ These Spells have many names:

Programs. Algorithms. Executables. Packages (collection of entities). Task units (concurrent computations). Protected Units (shared data between tasks). Generic Units.

It’s the basic unit for expressing an algorithm. There are two kinds: Procedures and Functions.

Procedures

Processes. Reflects into actions when called. They do actions.

procedure P (parameters : in out Param_type) is
  --  Declarations
begin 
  --  Statements
exception
  --  Handlers
end P;  

Functions

Processes that produce data. It returns a result when called. They do stuff.

function F (parameters : in out type) return Ftype is
  --  Declarations
begin 
 --  Statements
exception
  --  Handlers
end F; 

Declare and Define

How to declare and define functions in 2 steps...

Function Sqrt(F: Float) return Float;

We may want to do in two steps so we can use it and define later on the file.


Function Sqrt(F: Float) return Float is
  R: Float;
begin 
   ...  -- Computation For Sqrt in the Reals
   return R;
end Sqrt;

same for procedures

Specification and Body

The distinction allows a program to be designed, written, and tested, as a set of largely independent software components.

Parameters

They both may need parameters, or inputs, that are specified when called.

A task unit is a basic unit for a sequence of actions. Such tasks may be implemented on multicomputers, multiprocessors, or with interleaved execution on a single processor. A task unit may define either a single executing task or a task type permitting the creation of any number of similar tasks.

Una lista de parámetros formales se encierra entre paréntesis y está formada por una o más especificaciones de parámetros separadas por punto y coma. Cada especificación de parámetros está formada por una lista de identificadores separados por comas, seguida de dos puntos tras los que aparece el modo de paso y tipo de los parámetros. El tipo de parámetro puede ser una definición de puntero anónimo. El modo de paso de los parámetros puede ser in (entrada), out (salida) o in out (entrada y salida). El modo por omisión es in y es el único aplicable cuando el tipo de parámetro es una definición de puntero. Las funciones sólo admiten parámetros in. De forma opcional, se pueden asignar valores por omisión a los parámetros especificando una expresión por omisión (default_expression). El modificador de null_exclusion sólo es aplicable cuando el tipo de parámetro es un puntero (pero no una definición de puntero anónimo) y significa que el parámetro no puede tomar el valor null.

procedure Intercambiar (A, B : in out Integer);
procedure Mezclar (L1, L2 : in Lista; L3 : out Lista);
function Combinatorio (M, N : Natural) return natural;

Simple Example

To understand the Language let us start with a simple example:

hello.adb

with Ada.Text_IO;    --Input Output Standard Library

procedure Hello is
begin 
   --  Print "Hello,  Ada!" to the screen
   Ada.Text_IO.Put_Line(“Hello, Ada!”);
end Hello;

You will may have noticed the following:

  1. No curly brackets
  2. Begin-End delimiters
  3. Very verbose, little “programming symbols”
  4. The symbols used are following mathematic standards.
  5. The name of the process (it’s not main and) it’s declared with the type of unit it is.
  6. End clause has the name of the process it’s ending. Just good practice, not mandatory.
  7. Ada is NOT case sensitive.
  8. Semicolons ; are sentence terminators
  9. Double hyphen -- are line comments
  10. Whitespace characters are ignored beyond the first character.

Between is and begin we write declarations.
Between begin and end we write statements.

El cuerpo de una función consta de: una especificación formada por un identificador (defining_designator), una lista de parámetros opcional (formal_part) y un result_profile que especifica el tipo del resultado que devuelve la función; una secuencia de declaraciones (declarative_part) y, encerrada en un bloque begin..end, la secuencia de sentencias ejecutables, que debe incluir al menos una sentencia de retorno con el resultado de la ejecución de la función. El end del final de la función puede ir acompañado (se recomienda) de un designator que debe coincidir con el identificador de la función. Si la función es una unidad de librería, el identificador de la función puede incluir el nombre de la unidad padre (parent_unit_name). El cuerpo de la función puede ir precedido de un indicador de overriding, si sustituye a una operación primitiva de algún tipo. El cuerpo de una función completa una declaración previa, o sirve de declaración en caso de que no haya habido ninguna previa.

function Suma (A, B: Integer) return Integer is
   begin
   return A + B;  --  No se puede omitir
   end Sumar;

Sentencia de retorno simple.

Termina la ejecución de un subprograma. Exclusivamente en el caso de las funciones, debe llevar asociada una expresión que representa el valor a devolver como resultado de la ejecución de la función.

procedure Sumar (A, B: in Integer; S : out Integer) is
   begin
   S := A + B;
   return;    --  Si se omite se tiene el mismo efecto 
   end Sumar;
function Suma (A, B: Integer) return Integer is
   begin
   return A + B;  --  No se puede omitir
   end Sumar;
function Suma (A, B: Integer) return Integer;
...
X, Y, Z : Integer;
R       : Float;
...
--  Llamadas asignando el resultado a una variable
Z := Suma (3, Y);
Z := Suma (X, Y);
Z := Suma (X, B => Y);
--  Llamadas Integradas en expresiones
if Suma (X, Y) > Z then
   ...
end if;
Z := Suma (X, Y) * 10;
R := Float (Suma (X, Y)) / 10.0;