begin

Transkrypt

begin
Podprogramy, pakiety, typy
prywatne i struktura programu
•
Podprogramy
•
Pakiety i typy prywatne
•
Struktura programu
Funkcje
Funkcja jest podprogramem, który może być wywołany w
kontekście wyrażenia.
function Sqrt(X: Float) return Float is
R: Float;
begin
-- compute value of Sqrt(X) in R
return R;
end Sqrt;
Przykłady list parametrów:
(I, J, K: Integer)
(Left: Integer; Right: Float)
Specyfikacja funkcji bez podawania jej treści:
function Sqrt(X: Float) return Float;
Parametry podprogramów mogą mieć tryby in, in out i out.
Do Ady 2005 włącznie funkcje mogły mieć parametry tylko w
trybie in.
Parametr formalny w trybie in zachowuje się jak stała, której
wartość dostarczana jest w wywołaniu odpowiednim
parametrem aktualnym.
Dla przykładu rozpatrzmy obliczenie:
S := Sqrt(T + 0.5);
wówczas obliczana jest wartość T + 0.5, następnie
wewnątrz treści funkcji Sqrt parametr formalny X zachowuje
się jak:
X: constant Float := T + 0.5;
Treść funkcji może mieć wiele instrukcji powrotu:
function Sign(X: Integer) return Integer is
begin
if X > 0 then
return +1;
elsif X < 0 then
return -1;
else
return 0;
end if;
end Sign;
Każde wywołaniu funkcji tworzy nowe przykłady obiektów
zadeklarowanych w jej wnętrzu (łącznie z parametrami), które
znikają gdy opuszczamy funkcję. Zatem jest
możliwość rekurencyjnego wywoływania funkcji:
function Factorial(N: Positive) return Positive is
begin
if N = 1 then return 1;
else return N * Factorial(N-1);
end if;
end Factorial;
Nie ma potrzeby sprawdzania czy parametr N jest dodatni, bo
został zadeklarowany jako Positive. Zatem wywołanie
Factorial(-2) spowoduje wyjątek Constraint_Error.
Wywołanie Factorial(10_000) możne spowodować
wyczerpanie się pamięci i zgłoszenie wyjątku
Storage_Error, natomiast Factorial(50)
najprawdopodobniej spowoduje zgłoszenie
Constraint_Error.
Parametr formalny może być dowolnego typu ale w ogólności
musi być to typ nazwany. W szczególnych przypadkach
dopuszczalne są typy anonimowe np. wskaźnikowe.
Parametr formalny może być nieograniczonego typu
tablicowego jak np.
type Vector is array (Integer range <>) of Float;
W takim przypadku zakresy formalnego parametru
zostaną przyjęte z parametru aktualnego:
function Sum(A: Vector) return Float is
Result: Float := 0.0;
begin
for I in A'Range loop
Result := Result + A(I);
end loop;
return Result;
end Sum;
Możemy wówczas napisać:
V: Vector(1 .. 4) := (1.0, 2.0, 3.0, 4.0);
S: Float:
...
S := Sum(V);
Przykład:
function Inner(A, B: Vector) return Float is
Result: Float := 0.0;
begin
for I in A'Range loop
Result := Result + A(I)*B(I);
end loop;
end Inner;
...
V: Vector(1 .. 3) := (1.0, 2.0, 3.0);
W: Vector(1 .. 3) := (2.0, 3.0, 4.0);
X: Float:
...
X := Inner(V, W); -- 1.0*2.0+2.0*3.0+3.0*4.0
Powinno sprawdzać się zakresy tablic:
if A'First /= B'First or A'Last /= B'Last then
raise Constarint_Error;
end if;
Funkcja może mieć parametr będący ograniczonym typem
tablicowym ale musi być on nazwany:
function Sum_5(A: Vector(1 .. 5)) return Float
-- illegal
subtype Vector_5 is Vector(1 .. 5);
...
function Sum_5(A: Vector_5) return Float
Parametr aktualny musi mieć tyle samo elementów zatem
plasterki są dopuszczalne jak przy instrukcji podstawienia:
W: Vector(0 .. 4);
...
S := Sum_5(W);
Wartość funkcji również może być nieograniczonego typu
tablicowego:
function Rev(A: Vector) return Vector is
R: Vector(A'Range);
begin
for I in A'Range loop
R(I) := A(A'First + A'Last - I);
end loop;
return R;
end Rev;
Wartość będąca tablicą zwracaną przez funkcję może
być indeksowana:
Rev(Y)(I)
Funkcje bezparametrowe wywołuje się bez nawiasów aby nie
było niejednoznaczności gdy indeksuje się ich wynik. Zatem
gdy F jest bezparametrową funkcją zwracającą tablicę, to
F(I) jest elementem zwracanej tablicy.
Rozszerzona postać instrukcji powrotu:
function Rev(A: Vector) return Vector is
begin
return R: Vector(A'Range) do
for I in A'Range loop
R(I) := A(A'First + A'Last - I);
end loop;
end return;
end Rev;
W szczególnych przypadkach część do .. end return
może być pominięta:
function Zero return Complex is
begin
return C: Complex;
end Zero;
W Ada 2012, jeśli funkcja jest krótka, to może być zapisana
jako wyrażenie funkcyjne bez instrukcji return:
function Sign(X: Integer) return Integer is
(if X > 0 then +1 elsif X < 0 then -1 else 0);
W Ada 2012 funkcje mogą mieć parametry innych trybów
niż tylko in:
function My_Random(Seed: in out Integer) return Integer is
N: constant Integer := ...;
M constant Integer := ...;
begin
Seed := Seed * N mod M;
return Seed;
end My_Random;
Operatory
Nazwą definiowanej funkcji może być łańcuch znaków będący
nazwą jednego operatora dostępnego w języku Ada:
abs and mod not or
= /= < <=
+ - * / **
> >=
&
rem xor
iloczyn wektorowy
function "*"(A, B: Vector) return Float is
Result: Float := 0.0;
begin
for I in A'Range loop
Result := Result + A(I)*B(I);
end loop;
iloczyn liczb rzeczywistych
return Result;
end "*";
...
X := Inner(V, W);
...
X := V * W;
Procedury
•
•
•
procedura rozpoczyna się słowem kluczowym procedure,
nazwa procedury musi być identyfikatorem,
nie zwraca wyniku.
in Parametr formalny jest stałą inicjowaną wartością
odpowiedniego parametru aktualnego.
in out Parametr formalny jest zmienną inicjowaną aktualnym
parametrem i pozwala na czytanie i uaktualnianie wartości
odpowiedniego parametru aktualnego.
out Parametr formalny jest niezainicjowaną zmienną; pozwala
na uaktualnianie wartości odpowiedniego parametru
aktualnego.
procedure Add(A, B: in Integer; C: out Integer) is
begin
C := A + B;
end Add;
...
P, Q: Integer;
...
Add(2 + P, 37, Q);
Powyższe wywołanie odpowiada „mniej więcej” wykonaniu:
declare
A: constant Integer := 2 + P; -- in
B: constant Integer := 37; -- in
C: Integer; -- out
begin
C := A + B; -- body
Q := C; -- out
end;
procedure Increment(X: in out Integer) is
begin
X := X + 1;
end Increment;
...
I: Integer;
...
Increment(I);
Powyższe wywołanie odpowiada „mniej więcej” wykonaniu:
declare
X: Integer := I;
begin
X := X + 1;
I := X;
end;
procedure Quadratic(
A, B, C: in Float;
Root_1, Root_2:
out Float; OK: out Boolean) is
D: constant Float := B**2 - 4.0*A*C;
begin
if D < 0.0 or A = 0.0 then
OK := False;
return;
end if;
Root_1 := (-B - Sqrt(D)) / (2.0*A);
Root_2 := (-B + Sqrt(D)) / (2.0*A);
OK := True;
end Quadratic;
procedure Quadratic(
A, B, C: in Float;
Root_1, Root_2:
out Float; OK: out Boolean) is
D: constant Float := B**2 - 4.0*A*C;
begin
OK := D >= 0.0 and A /= 0.0;
if not OK then
return;
end if;
Root_1 := (-B - Sqrt(D)) / (2.0*A);
Root_2 := (-B + Sqrt(D)) / (2.0*A);
OK := True;
end Quadratic;
Aliasing
procedure Do_It(Double, Triple: in out Integer) is
begin
Double := Double * 2;
Triple := Triple * 3;
end Do_It;
...
Var: Integer := 2;
...
Do_It(Var, Var); -- illegal in Ada 2012
-- F has in out parameter
Var := F(Var); -- illegal
Proc(Var, F(Var)); -- illegal
ProcA(A, F(A(K))); -- illegal
ProcR(R, F(R.C)); -- illegal
Proc(A(J), F(A(K))); -- OK but problem when J = K
Nazwane i domyślne
parametry
Quadratic(A => L, B => M, C => N, Root_1 => P, Root_2 => Q, OK =>
Status);
Increment(X => I);
Add(C => Q, A => 2+P, B => 37);
F := Factorial(N => 4);
S := Sqrt(X => T + 0.5);
X := Inner(B => W, A => V);
Quadratic(L, M, N, Root_1 => P, Root_2 => Q, OK => Status);
type Spirit is (Gin, Vodka);
type Style is (On_The_Rock, Straight_Up);
type Trimming is (Olive, Twist);
...
procedure Dry_Martini(
Base: Spirit := Gin;
How: Style := On_The_Rocks;
Plus: Trimming := Olive);
...
Dry_Martini(How => Straight_Up);
Dry_Martini(Vodka, Plus => Twist);
Dry_Martini;
Dry_Martini(Gin, Straight_Up);
Przeciążanie
type Garment is (Guernsey, Jersey, Alerney);
type Cow is (Guernsey, Jersey);
procedure Sell(Style: Garment);
procedure Sell(Breed: Cow);
Sell(Alderney); -- not ambiguous
Sell(Jersey); -- ambiguous
Sell(Cow'(Jersey)); -- ok
Sell(Breed => Jersey); -- ok
Deklaracje, zakres i
widoczność
procedure P is
J: Integer := 0;
…
procedure Q is
K: Integer := J;
J: Integer := 0;
L: Integer := P.J;
begin
…
end Q;
…
begin
…
end P;
Scope of
outer J
Outer J
visible
Outer J
directly
visible
LL: for I in AA'Range(1) loop -- a little crazy example
for I in AA'Range(2) loop
AA(LL.I, I) := 0.0;
end loop;
end loop LL;
Pakiety i typy prywatne
Struktura programu