[nem-pl] z cyklu oglądamy i krytykujemy
olszta at tey.pl
olszta at tey.pl
Thu Nov 6 17:25:44 CET 2003
Ja to jeszcze powolutku przemysle, ale...
Mamy trzy rodzaje asercji: zwykle eiffelowe, straznikow dla zmiennych
i straznikow dla blokow. Dodatkowo dodajemy pojecie transakcji, w czasie
jej wykonywania obudzeni straznicy odkladani sa na stos i uruchamiani
po jej zakonczeniu. Oprocz tego dodajemy atrybut pure dla funkcji, ktory
oznacza ze funkcja nie ma efektow ubocznych (modulo allokacja pamieci).
I na dokladke slowa kluczowe: value i previous.
Wyglada to tak:
0) definiujemy atrybut pure
Da sie to latwo sprawdzic, jesli czasami bedziemy mogli sklamac.
1) warunek poczatkowy dla bloku wykonywalnego:
require { [warunek]; [warunek]; ... }
Gdzie [warunek]; to cokolwiek pure, co ewaluuje sie do boola.
Warunki sa sprawdzane w momencie wejscia do bloku.
2) warunek koncowy dla bloku wykonywalnego:
ensure { [warunek]; [warunek]; ... }
Podobnie jak wyzej, ale sprawdzane w momencie wyjscia z bloku,
dodatkowo mozliwosc skorzystania ze slowa kluczowego value, ktore
oznacza wartosc zwracana z danego bloku.
3) straznik dla bloku wykonywalnego:
guard { [warunek]; [warunek]; ... }
To sa niezmienniki na poziomie calego bloku, podobnie jak require,
ale sprawdzane po kazdej instrukcji w bloku, a nie tylko na jego
koncu (tu oczywiscie mozliwe sa pewne optymalizacje, ale to nie
jest istotne w tej chwili).
Tutaj jest taki problem, ze to jest bardzo fajne, jesli mamy
zdefiniowane petle w jezyku (np. while). Inaczej przydaje sie to
tylko w bardzo prostych programach.
4) straznik dla zmiennej:
guarded [nazwa zmiennej] : [typ]
{
[warunek]; [warunek]; ...
}
Takie zmienne mozna definiowac zarowno w klasach, jak i w funkcjach
i zachowuja sie one dokladnie, jak zmienne mutable.
Przy kazdej probie zapisu do takiej zmiennej, sa sprawdzane warunki.
Mozna skorzystan z kwalifikatora previous (np. previous.x) aby uzyskac
dostep do poprzedniej wartosci zmiennej.
Trzeba dokladnie przemyslec, kiedy zaczac uruchamiac straznikow
(np. nie w czasie konstrukcji), ew. zwalic to na transaction.
5) straznik dla klas i wariantow
Syntaktycznie podobnie jak 3), ale dotyczy pol i funkcji klasy lub
wariantu.
-- PRZYKLAD --------------------
class Factorial
{
guard
{
_n * _accumulator < System.Int32.MaxInt;
}
public guarded _n : int
{
_n >= 0;
previous._n > _n;
}
public guarded _accumulator : int
{
_accumulator >= 1;
previous._accumulator < _accumulator;
}
public Step () : void
{
require { _n > 1; }
transaction
{
_accumulator *= _n;
_n--;
}
}
public PerformSteps () : void
{
if (_n > 1) { Step(); PerformSteps(); }
}
public CalculateFactorial (n : int) : int
{
transaction
{
_n = n;
_accumulator = 1;
}
PerformSteps ();
_n;
ensure { _n > 0; }
}
}
More information about the devel-pl
mailing list