FEN KbP/seminar2: design21 Kontraktbaseret programmering Seminar 2 Klassedesign: Immutable lister Queue Shallowcopy og alkvantoren
FEN KbP/seminar2: design22 Immutable (uforanderlige) lister Hvis man ikke har kvantorer, så kan immutable lister anvendes i specifikationer, som skal udtale sige om egenskaber ved mange elementer Immutable lister ligner lister i LISP (og andre funktionssprog som fx F#) Er specielt designet til at anvendes i udtryk (en specifikation er et logisk udtryk) Er rekursive i natur, specifikation og implementation Vi kan udtale os om mængder af elementer ved rekursive listeudtryk Immutable datastrukturer anvendes intensivt i funktionelle sprog (fx F#) og parallelle systemer
FEN KbP/seminar2: design23 List-interfacet (Bemærk: ingen kommandoer) public interface ImmutableList { // Basic queries public boolean isEmpty(); public Object head(); public ImmutableList tail(); // Derived queries public int size(); public ImmutableList precededBy(Object o); public boolean equals(ImmutableList l); public Object item(int i); public ImmutableList sublist(int from, int to); } Opbygger listen ved at sætte elementer ind foran den eksisterende (evt. tomme) liste og returnere en ny liste med o indsat forrest.
FEN KbP/seminar2: design24 Specifikationen public interface ImmutableList { // Basic queries public boolean isEmpty(); requires public Object head(); requires public ImmutableList tail(); // Derived queries ensures isEmpty() ==> ensures (!isEmpty()) ==> (\result == public int size(); A= (a, b, c, d) A.head() = a A.tail() = (b, c, d) Bemærk, rekursion
FEN KbP/seminar2: design25 ensures ensures (\result).tail() == ensures (\result).head() == public ImmutableList precededBy(Object o); requires l != ensures (l.isEmpty() != isEmpty()) ==> ensures (!isEmpty()) ==> (\result == (l.head()==head() public boolean equals(ImmutableList l); requires 0<=i && ensures (i==0) ==> ensures (i>0) ==> public Object item(int i); A= () A.precededBy(a) = (a) A.precededBy(b) = (b, a) … Bemærk, rekursion
FEN KbP/seminar2: design26 requires 0<=from && from<=to && ensures ensures (from!=to) ==> ensures (from!=to) ==> public ImmutableList sublist(int from, int to); Bemærk, rekursion implementation demo
FEN KbP/seminar2: design27 Brug af immutable lister i specifikation: Queue public interface Queue2 { invariant // Basic queries public ImmutableList items(); // Derived queries ensures \result == public int size(); ensures public boolean isEmpty(); requires ensures public Object head(); Returnerer en liste med køens elementer items() anvendes ved specifikation af de øvrige operationer Burde være ”pure”, men det acceptere JML ikke umiddelbart
FEN KbP/seminar2: design28 // Commands ensures ensures public void put(Object o); requires ensures ensures public void remove(); } Operationer på ImmutableList anvendes
FEN KbP/seminar2: design29 Diskussion Omkostninger: –Alle disse ekstra lister, som traverseres - og det endda rekursivt - må give et enormt overhead i tids- og pladsforbrug! –Ja, men: Check af postbetingelser afslører fejl i klassens implementation og er vigtig ved udvikling og debuging. Check af prebetingelser afslører fejl hos klienten og er vigtig, når klassen anvendes. Sørg for at prebetingelser kan checkes effektivt! (Fx en count-attribut). Indkapsling: –Bryder items() ikke med indkapsling af køen? –Nej, jf. diskussionen i forbindelse med Stack Det ville være noget andet, hvis vi kunne fjerne eller indsætte midt i køen
FEN KbP/seminar2: design210 Et design med kvantorer Hvis kvantorer understøttes, så kan immutable lister undværes. Vi har stadig behov for at kunne udtale os om mange elementer både før og efter udførelsen af en operation Dette kan gøres ved at tage en shallow copy af strukturen inden operationen udføres En shallow copy er en kopi af strukturen, men med de samme elementer:
FEN KbP/seminar2: design211 Specifikation af shallowCopy() ensures ensures (\forall int i; 0<=i && public Queue shallowCopy(); Bemærk, ’==’ Dvs. samme objektreference skal returneres af kopien som af originalen
FEN KbP/seminar2: design212 Specifikation af Queue vha. kvantorer og shallowCopy() public interface Queue { invariant // Basic queries public int size(); requires 0<=i && public Object get(int i); // Derived queries requires ensures \result == public Object head(); ensures \result == public boolean isEmpty(); ensures ensures (\forall int i; 0<=i && i<=size()-1; public Queue shallowCopy(); Burde være ”pure”, men det acceptere JML ikke umiddelbart
FEN KbP/seminar2: design213 // Commands ensures ensures public void put(Object o); requires ensures ensures (\forall int i; 0<=i && \old(shallowCopy()).get(i+1) == public void remove(); Her benyttes en kopi taget inden remove() udføres. Specifikationen udtrykker, at alle elementer er rykket en plads længere frem i køen Behøver vi shallowCopy(), eller kunne vi bare skrive \old(get(i+1)) == get(i) ? (Afhænger af impl. af \old(-))