0
Andrea Schiavinato, Marzo 2008
<ul><li>Speigare come si usa  iContract , un tool semplice e gratuito per applicare la tecnica del  Design by Contract a J...
<ul><li>Una metodologia per creare programmi OO di  maggior qualità , in modo più  formale  e  sicuro </li></ul><ul><li>Si...
<ul><li>Il tool prende in input file .java annotati con asserzioni e produce in output gli stessi file .java con l’aggiunt...
<ul><li>I due siti di riferimento sono:  </li></ul><ul><ul><li>http://icontract2.org </li></ul></ul><ul><ul><li>http://sou...
<ul><li>I commenti per JavaDoc sono delimitati da /** e */ </li></ul><ul><li>L’attributo “pre” serve per specificare le pr...
<ul><li>Il Main (scritto in Esempio1.java): public static void main(String[] args) {   System.out.println(div(10, 2));   S...
<ul><li>java  -cp $CLASSPATH:/usr/lib/jvm/java-6-sun-1.6.0.03/lib/tools.jar:.:_contract_db:instr:icontract-jdk1_1_7.orig.j...
Esempio1.java __REP_Esempio1.java   __REP_Esempio1.class Esempio1.java File usati da JContract per gestire l’ereditarietà ...
Lo script “BUILD” contiene il comando per la compilazione con iContract
<ul><li>Abbiamo informazioni precise su quale inv./prec./postc. è stato violata e, se si tratta di un invariante, in quale...
<ul><li>Il codice aggiunto per controllare la precondizione: </li></ul>/*|*/ try { /*|*/  boolean __pre_passed = false;  /...
<ul><li>Gestire gli uffici  di un’azienda, supportare  l’assunzione  di nuovi membri assegnando loro un ufficio libero e c...
<ul><li>Vediamo più approfonditamente la sintassi delle asserzioni di iContract: </li></ul><ul><li>{@inv|@pre|@post} espre...
<ul><li>Tutti gli impiegati devono avere un ufficio </li></ul><ul><li>Gli impiegati devono avere uffici differenti </li></...
<ul><li>Nessuna precondizione </li></ul><ul><li>Come postcondizioni: </li></ul><ul><ul><li>Restituisce true se e solo se e...
<ul><li>Precondizioni: </li></ul><ul><ul><li>Ci deve essere almeno un ufficio disponibile </li></ul></ul><ul><li>Postcondi...
<ul><li>Precondizioni: </li></ul><ul><ul><li>i ≠ null, i non è già stato assunto </li></ul></ul><ul><ul><li>c’è un ufficio...
<ul><li>Precondizioni: </li></ul><ul><ul><li>i ≠ null, u ≠ null, u è disponibile </li></ul></ul><ul><li>Postcondizioni: </...
<ul><li>return == exists Ufficio u in getUffici().elements() | u.disponibile() return == (exists Ufficio u in getUffici()....
<ul><li>Ora  utilizziamo un’implementazione “misteriosa”  di quest’interfaccia che consiste nelle classi AziendaImpl, Impi...
E’ sbagliato il nostro main o l’implementazione? Non ci sono più uffici o non si possono inserire altri impiegati?
Ora sappiamo che la responsabilità è nostra  (che abbiamo scritto il main), in quanto abbiamo violato la precondizione uff...
public static void main(String[] args) { Azienda luthorCorp = new AziendaImpl(); Impiegato i1 = new ImpiegatoImpl(&quot;Li...
<ul><li>Ci giunge un’informazione sull’implementazione usata: è possibile specificare il numero di uffici nel costrutture ...
<ul><li>Per il  programmatore </li></ul><ul><ul><li>Quando si cambia l’implementazione di un metodo, p.e. per renderlo più...
<ul><li>PRO: </li></ul><ul><li>Semplice scrivere invarianti </li></ul><ul><li>Non richiede molti sforzi per poter essere u...
<ul><li>iDoclet </li></ul><ul><li>http://icplus.sourceforge.net/icplus.html </li></ul><ul><li>Un’estensione della doclet s...
Upcoming SlideShare
Loading in...5
×

iContract

548

Published on

iContract, a tool that allows Design by Contract in Java

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total Views
548
On Slideshare
0
From Embeds
0
Number of Embeds
0
Actions
Shares
0
Downloads
1
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide
  • Transcript of "iContract"

    1. 1. Andrea Schiavinato, Marzo 2008
    2. 2. <ul><li>Speigare come si usa iContract , un tool semplice e gratuito per applicare la tecnica del Design by Contract a Java </li></ul><ul><li>Scaletta: </li></ul><ul><ul><li>Qualche richiamo al Design by Contract </li></ul></ul><ul><ul><li>Introduzione allo strumento </li></ul></ul><ul><ul><li>Un primo semplice esempio </li></ul></ul><ul><ul><li>Secondo esempio: gestione degli uffici di un’azienda </li></ul></ul><ul><ul><li>Benefici del Design by Contract in generale </li></ul></ul><ul><ul><li>Valutazione dello strumento </li></ul></ul>
    3. 3. <ul><li>Una metodologia per creare programmi OO di maggior qualità , in modo più formale e sicuro </li></ul><ul><li>Si “decora” una classe con espressioni booleane di tre tipi: </li></ul><ul><ul><li>INVARIANTI, a livello di classe, devono valere in ogni momento </li></ul></ul><ul><ul><li>PRECONDIZIONI, a livello di metodo, devono valere subito prima dell’esecuzione della prima istruzione di un metodo </li></ul></ul><ul><ul><li>POSTCONDIZIONI, a livello di metodo, devono valere subito dopo l’esecuzione dell’ultima istruzione di un metodo </li></ul></ul>
    4. 4. <ul><li>Il tool prende in input file .java annotati con asserzioni e produce in output gli stessi file .java con l’aggiunta di istruzioni che controllano esplicitamente la validità delle asserzioni nei momenti opportuni </li></ul><ul><li>Nel caso in cui un’asserzione fallisca viene generata un’eccezione </li></ul><ul><li>Invarianti, precondizioni e postcondizioni espressi sotto forma di commenti associati a classi o metodo </li></ul><ul><li>Sintassi di JavaDoc </li></ul><ul><li>Espressività: logica del prim’ordine, compresi i quantificatori universali ed esistenzali </li></ul>
    5. 5. <ul><li>I due siti di riferimento sono: </li></ul><ul><ul><li>http://icontract2.org </li></ul></ul><ul><ul><li>http://sourceforge.net/projects/jcontracts (più recente, ma l’ultimo aggiornamento risale a Novembre 2006) </li></ul></ul><ul><li>Le versioni disponibili sono </li></ul><ul><ul><li>icontract (nome del file: icontract-jdk1_1_7.orig.jar) </li></ul></ul><ul><ul><li>icontract2 (nome del file: iContract2.jar) </li></ul></ul><ul><ul><li>Jcontracts (nome del file: jcontracts-1.01.00b01.jar) </li></ul></ul><ul><li>Nella sostanza sono tutte uguali: cambia il nome del pakage e i file .jar delle ultime due versioni non incorporano le librerie antlr e log4j, che devono perciò essere presenti nel classpath al momento dell’esecuzione </li></ul><ul><li>Userò la prima versione (del ‘99), perché la trovo più comoda </li></ul>
    6. 6. <ul><li>I commenti per JavaDoc sono delimitati da /** e */ </li></ul><ul><li>L’attributo “pre” serve per specificare le precondizioni </li></ul><ul><li>L’attributo “post” le postcondizioni </li></ul><ul><li>I valori sono espressioni booleane con la sintassi Java </li></ul><ul><li>Lo scope delle espressioni è quello del metodo </li></ul>public class Esempio1 { /** * Effettua una divisione intera * * @param x il divisore * @param y il dividendo * @return il quoziente * @pre (x >= 0) && (y>0) * @post x == (quo*y + rem) * @post rem < y */ public static int div(int x, int y) { int quo = 0; int rem = x; while (rem >= y) { rem -= y; quo++; } return quo; } … }
    7. 7. <ul><li>Il Main (scritto in Esempio1.java): public static void main(String[] args) { System.out.println(div(10, 2)); System.out.println(div(2, 0)); } </li></ul><ul><li>div(2, 0) non termina! </li></ul>public class Esempio1 { /** * Effettua una divisione intera * * @param x il divisore * @param y il dividendo * @return il quoziente * @pre (x >= 0) && (y>0) * @post x == (quo*y + rem) * @post rem < y */ public static int div(int x, int y) { int quo = 0; int rem = x; while (rem >= y) { rem -= y; quo++; } return quo; } … }
    8. 8. <ul><li>java -cp $CLASSPATH:/usr/lib/jvm/java-6-sun-1.6.0.03/lib/tools.jar:.:_contract_db:instr:icontract-jdk1_1_7.orig.jar iContract.Tool -a -v -minv,pre,post - b&quot;javac -classpath $CLASSPATH:.&quot; -c&quot;javac -classpath $CLASSPATH:instr&quot; -n&quot;javac -classpath $CLASSPATH:_contract_db:instr&quot; -oinstr/@p/@f.@e -k_contract_db/@p Esempio1.java </li></ul>Classpath: occorre il file tools.jar, perché iContract usa la classe sun.Tools.javac Classe base : il percorso dipende dalla versione di iContract usata, comunque il suo nome è sempre Tool Genera tutti i file anche se esistono già classi elaborate ed aggiornate Stampa tutti gli avvisi Viene generato il codice che controlla invarianti, precondizioni e postcondizioni Comandi per compilare i file in input all’inizio, i file “repository” ed i file prodotti con i controlli delle asserzioni Posizione dei file con i controlli Posizione dei file “repository” Il file in input (si può usare il carattere jolly *)
    9. 9. Esempio1.java __REP_Esempio1.java __REP_Esempio1.class Esempio1.java File usati da JContract per gestire l’ereditarietà (non ci interessano) Il nostro programma con l’aggiunta di istruzioni per il controllo esplicito di invarianti/precondizioni/postcondizioni Esempio1.class iContract.Tool()
    10. 10. Lo script “BUILD” contiene il comando per la compilazione con iContract
    11. 11. <ul><li>Abbiamo informazioni precise su quale inv./prec./postc. è stato violata e, se si tratta di un invariante, in quale momento </li></ul><ul><li>In questo caso l’errore è del cliente del metodo, che non ha rispettato la precondizione </li></ul>
    12. 12. <ul><li>Il codice aggiunto per controllare la precondizione: </li></ul>/*|*/ try { /*|*/ boolean __pre_passed = false; // true if at least one pre-cond conj. passed. /*|*/ // checking Esempio1::div(int,int) /*|*/ if (! __pre_passed ) { /*|*/ if ( ((x > 0) && (y>0) /* do not check prepassed */ )) __pre_passed = true; // succeeded in: Esempio1::div(int,int) /*|*/ else /*|*/ __pre_passed = false; // failed in: Esempio1::div(int,int) /*|*/ } /*|*/ if (!__pre_passed) { /*|*/ throw new RuntimeException (&quot;Esempio1.java:14: error: precondition violated (Esempio1::div(int,int)): (/*declared in Esempio1::div(int,int)*/ ((x > 0) && (y>0))) &quot; /*|*/ ); }} /*|*/ catch ( RuntimeException ex ) { /*|*/ String txt = &quot;&quot;; if (ex.getClass()==RuntimeException.class) { txt = ex.toString();; } /*|*/ else txt = &quot;Esempio1.java:14: exception <<&quot;+ex+&quot;>> occured while evaluating PRE-condition in Esempio1.java:14: Esempio1::div(int,int)): (/*declared in Esempio1::div(int,int)*/ ((x > 0) && (y>0))) &quot; /*|*/ ; /*|*/ throw new RuntimeException(txt);}
    13. 13. <ul><li>Gestire gli uffici di un’azienda, supportare l’assunzione di nuovi membri assegnando loro un ufficio libero e consentire lo spostamento degli impiegati da un ufficio ad un altro </li></ul>0..n 0..n
    14. 14. <ul><li>Vediamo più approfonditamente la sintassi delle asserzioni di iContract: </li></ul><ul><li>{@inv|@pre|@post} espressione </li></ul><ul><li>espressione: </li></ul><ul><ul><li>può essere un’espressione booleana valida in Java </li></ul></ul><ul><ul><li>forall Oggetto o in <enumeration> | espressione </li></ul></ul><ul><ul><li>exists Oggetto o in <enumeration> | espressione </li></ul></ul><ul><ul><li><espressione> implies <espressione> </li></ul></ul><ul><li>Lo scope: </li></ul><ul><ul><li>L’invariante è come se fosse un metodo della classe </li></ul></ul><ul><ul><li>Le precondizioni e postcondizioni è come se fossero delle istruzioni all’interno del metodo a cui fanno riferimento </li></ul></ul><ul><li>Pseudovariabili consentite: </li></ul><ul><ul><li><espressione>@pre indica il valore dell’espressione prima che inizi l’esecuzione del metodo </li></ul></ul><ul><ul><li>return indica il valore restituito dalla funzione </li></ul></ul>
    15. 15. <ul><li>Tutti gli impiegati devono avere un ufficio </li></ul><ul><li>Gli impiegati devono avere uffici differenti </li></ul>* @invariant forall Impiegato imp in getImpiegati().elements() | * getUffici().contains(imp.getUfficio()) * @invariant forall Impiegato imp1 in getImpiegati().elements() | * forall Impiegato imp2 in getImpiegati().elements() | * (imp1 != imp2) implies (imp1.getUfficio() != imp2.getUfficio()) * Vanno scritti subito prima di “interface Azienda {…”
    16. 16. <ul><li>Nessuna precondizione </li></ul><ul><li>Come postcondizioni: </li></ul><ul><ul><li>Restituisce true se e solo se esiste un ufficio disonibile </li></ul></ul>/** *@return ci sono uffici disponibili?? *@post return implies exists Ufficio u in getUffici().elements() | u.disponibile() *@post !return implies forall Ufficio u in getUffici().elements() | !u.disponibile() */ public boolean ufficiDisponibili();
    17. 17. <ul><li>Precondizioni: </li></ul><ul><ul><li>Ci deve essere almeno un ufficio disponibile </li></ul></ul><ul><li>Postcondizioni: </li></ul><ul><ul><li>Il risultato non è null </li></ul></ul><ul><ul><li>L’ufficio restituito appartiene all’insieme degli uffici </li></ul></ul><ul><ul><li>Nessuno degli impiegati lavora nell’ufficio restituito </li></ul></ul>/** * Restituisce un ufficio disponibile * @return un ufficio disponibile * @pre ufficiDisponibili() * @post return != null * @post getUffici().contains(return) * @post forall Impiegato imp in getImpiegati().elements() | imp.getUfficio() != return */ public Ufficio prendiUfficioDisponibile();
    18. 18. <ul><li>Precondizioni: </li></ul><ul><ul><li>i ≠ null, i non è già stato assunto </li></ul></ul><ul><ul><li>c’è un ufficio libero per i </li></ul></ul><ul><li>Postcondizioni: </li></ul><ul><ul><li>i appartiene agli impiegati dell’azienda </li></ul></ul><ul><ul><li>ad i è stato assegnato uno degli uffici dell’azienda </li></ul></ul><ul><ul><li>L’ufficio disponibile dopo la chiamata del metodo deve essere diverso dall’ufficio che era disponibile prima. </li></ul></ul>/** * Inserisce un nuovo impiegato nell'azienda * @param i il neoassunto * @pre i != null * @pre !(getImpiegati().contains(i)) * @pre ufficiDisponibili() * @post getImpiegati().contains(i) * @post getUffici().contains( i.getUfficio() ) * @post prendiUfficioDisponibile()@pre != prendiUfficioDisponibile() */ public void assumi( Impiegato i );
    19. 19. <ul><li>Precondizioni: </li></ul><ul><ul><li>i ≠ null, u ≠ null, u è disponibile </li></ul></ul><ul><li>Postcondizioni: </li></ul><ul><ul><li>L’ufficio di i è u </li></ul></ul><ul><ul><li>u non è disponibile </li></ul></ul>/** * Sposta un impiegato dell'azienda in un ufficio * @param i l'impiegato che si vuole spostare * @param u il nuovo ufficio dell'impiegato * @pre i != null * @pre u != null * @pre u.disponibile() * @post i.getUfficio() == u * @post !u.disponibile() */ public void sposta( Impiegato i, Ufficio u );
    20. 20. <ul><li>return == exists Ufficio u in getUffici().elements() | u.disponibile() return == (exists Ufficio u in getUffici().elements() | u.disponibile()) exists Ufficio u in getUffici().elements() | u.disponibile()) == return Sembra che l’operatore == e le parentesi non funzionino bene se usate con exists o forall </li></ul><ul><li>!exists Impiegato imp in getImpiegati().elements() | imp.getUfficio() == return Qui non viene riconosciuta la negazione iniziale, quindi siamo costretti ad usare un forall. </li></ul><ul><li>@post prendiUfficioDisponibile() == return Usata come postcondizione del metodo prendiUfficioDisponibile (per verficare he il metodo non abbia side-effect visibile) provoca uno Stack Overflow quando eseguiamo il programma </li></ul>Queste asserzioni non funzionano :
    21. 21. <ul><li>Ora utilizziamo un’implementazione “misteriosa” di quest’interfaccia che consiste nelle classi AziendaImpl, ImpiegatoImpl, UfficioImpl. </li></ul><ul><li>Consideriamo il seguente test: </li></ul>public static void main(String[] args) { Azienda luthorCorp = new AziendaImpl(); Impiegato i1 = new ImpiegatoImpl(&quot;Lioner Lutor&quot;); Impiegato i2 = new ImpiegatoImpl(&quot;Lex Lutor&quot;); Impiegato i3 = new ImpiegatoImpl(&quot;Clark Kent&quot;); System.out.println(&quot;Proviamo ad assumere &quot; + i1); luthorCorp.assumi(i1); System.out.println(&quot;Proviamo ad assumere &quot; + i2); luthorCorp.assumi(i2); System.out.println(&quot;Proviamo ad assumere &quot; + i3); luthorCorp.assumi(i3); System.out.println(&quot;Fine.&quot;); }
    22. 22. E’ sbagliato il nostro main o l’implementazione? Non ci sono più uffici o non si possono inserire altri impiegati?
    23. 23. Ora sappiamo che la responsabilità è nostra (che abbiamo scritto il main), in quanto abbiamo violato la precondizione ufficiDisponibili()
    24. 24. public static void main(String[] args) { Azienda luthorCorp = new AziendaImpl(); Impiegato i1 = new ImpiegatoImpl(&quot;Lioner Lutor&quot;); Impiegato i2 = new ImpiegatoImpl(&quot;Lex Lutor&quot;); Impiegato i3 = new ImpiegatoImpl(&quot;Clark Kent&quot;); System.out.println(&quot;Proviamo ad assumere &quot; + i1); if (luthorCorp.ufficiDisponibili()) luthorCorp.assumi(i1); System.out.println(&quot;Proviamo ad assumere &quot; + i2); if (luthorCorp.ufficiDisponibili()) luthorCorp.assumi(i2); System.out.println(&quot;Proviamo ad assumere &quot; + i3); if (luthorCorp.ufficiDisponibili()) luthorCorp.assumi(i3); System.out.println(&quot;Fine.&quot;); }
    25. 25. <ul><li>Ci giunge un’informazione sull’implementazione usata: è possibile specificare il numero di uffici nel costrutture di “AziendaImpl” </li></ul>public static void main(String[] args) { Azienda luthorCorp = new AziendaImpl(5); Impiegato i1 = new ImpiegatoImpl(&quot;Lioner Lutor&quot;); Impiegato i2 = new ImpiegatoImpl(&quot;Lex Lutor&quot;); Impiegato i3 = new ImpiegatoImpl(&quot;Clark Kent&quot;); System.out.println(&quot;Proviamo ad assumere &quot; + i1); if (luthorCorp.ufficiDisponibili()) luthorCorp.assumi(i1); System.out.println(&quot;Proviamo ad assumere &quot; + i2); if (luthorCorp.ufficiDisponibili()) luthorCorp.assumi(i2); System.out.println(&quot;Proviamo ad assumere &quot; + i3); if (luthorCorp.ufficiDisponibili()) luthorCorp.assumi(i3); System.out.println(&quot;Un ufficio più grande per &quot; + i1); luthorCorp.sposta(i1, luthorCorp.prendiUfficioDisponibile()); System.out.println(i2 + &quot; prende l'ufficio di &quot; + i3); luthorCorp.sposta(i1, i3.getUfficio()); System.out.println(&quot;Fine.&quot;); }
    26. 26.
    27. 27. <ul><li>Per il programmatore </li></ul><ul><ul><li>Quando si cambia l’implementazione di un metodo, p.e. per renderlo più efficiente, è immediato vedere se le modifiche apportate hanno qualche errore </li></ul></ul><ul><ul><li>Documentazione , le asserzioni sono veloci da scrivere e definiscono in modo preciso le proprietà di una classe </li></ul></ul><ul><ul><li>Un metodo per trattare casi anormali </li></ul></ul><ul><ul><li>Non dobbiamo preoccuparci di controllare che i parametri siano corretti </li></ul></ul><ul><li>Per gli utenti delle classi </li></ul><ul><ul><li>Documentazione , è facile il funzionamento delle classi in termini di invarianti, precondizioni e postcondizioni </li></ul></ul><ul><ul><li>E facile individuare errori nell’utilizzo delle classi </li></ul></ul><ul><li>Per il tester </li></ul><ul><ul><li>Il Design by Contract costituisce un framework per svolgere test, debug e controllo di qualità </li></ul></ul><ul><ul><li>Ci sono delle informazioni per il black box testing </li></ul></ul>
    28. 28. <ul><li>PRO: </li></ul><ul><li>Semplice scrivere invarianti </li></ul><ul><li>Non richiede molti sforzi per poter essere usato efficacemente </li></ul><ul><li>Scaricabile gratuitamente da Internet </li></ul><ul><li>CONTRO: </li></ul><ul><li>Progetto apparentemente abbandonato </li></ul><ul><li>Non supporta le novità di Java 5 (in particolare i tipi generici) </li></ul><ul><li>Un po’ difficile compilare i programmi con questo strumento </li></ul><ul><li>Le asserzioni talvolta non vengono interpretate come vogliamo </li></ul>
    29. 29. <ul><li>iDoclet </li></ul><ul><li>http://icplus.sourceforge.net/icplus.html </li></ul><ul><li>Un’estensione della doclet standard di Java che, usata con il tool javadoc, permette la creazione automatica di documentazione che include invarianti di classe e precondizioni/postcondizioni di ogni metodo. </li></ul>
    1. A particular slide catching your eye?

      Clipping is a handy way to collect important slides you want to go back to later.

    ×