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