Sei sulla pagina 1di 27

Capitolo 8

CONTROLLO DEL FLUSSO DI CONTROLLO:


1 . BLOCK STRUCTURED LANGUAGES 2 . ECCEZIONI

controllo del controllo gi dagli anni 60 risultato chiaro che i salti incontrollati rendono i programmi difficili da capire questa difficolt si rispecchia anche a livello implementativo la struttura della pila dei record dattivazione non basterebbe

come trattare un salto in un nuovo blocco ?


o in una funzione senza invocarla?

NON si POSSONO ACCETTARE !


negli anni 60 erano importanti per lefficienza
2

ma nel 68 Edsger W. Dijkstra manda una lettera alleditore delle Communications of the ACM Goto considered harmful

the qualiy of programmers is a decreasing function of the density of goto statements in the programs they produce..
goto statements should be abolished from all higher level programming languages.

per qualche salto serve, ma controllato


if_then_else, while, for, case, break, continue e anche eccezioni che sono salti da un blocco verso blocchi che lo racchiudono
4

le eccezioni servono a:
1) uscire da un blocco o dal corpo di una funzione 2) trasportare dei dati dal punto in cui si inizia il salto al punto di arrivo

3) ritornare ad una particolare istruzione del programma da cui si vuole continuare il calcolo
ci sono eccezioni in ADA, C++, Clu, Java, ML eccetera gestire eccezioni significa anche compiere azioni da fare sullo stack dei RA
5

il meccanismo per la gestione delle eccezioni consiste almeno di 2 parti: lancio delleccezione (raise, throw) trattamento delleccezione (handle, catch) in un programma ci possono essere molti handler per una eccezione (in diversi punti del programma) quale usare per trattare una data eccezione? scoping statico o dinamico?

si consideri una raise che appartiene ad una funzione f: scoping statico: si usa lhandler pi vicino alla raise nella definizione di f scoping dinamico: si usa lhandler pi vicino alla raise quando essa viene eseguita scoping dinamico lunica scelta ragionevole e a volte anche una scelta obbligata:

pensate se f parte di una libreria !!!


7

conoscete gi le eccezioni del C++

try, throw e catch


la selezione del catch segue la regola dello scoping dinamico e, in caso di pi catch allo stesso livello, la scelta avviene sulla base del tipo delleccezione sollevata entrano in gioco le regole delloverloading e delle conversioni automatiche tra tipi quindi guardiamo quelle del ML
8

handlers

<esp1> handle <pattern> => <esp2>


semantica: si esegue <esp1> se restituisce un valore v allora il valore dellintera espressione v se solleva uneccezione che fa match con <pattern> allora il valore dellintera espressione quello di <esp2> se leccezione non fa match con <pattern> oppure <esp2> solleva una nuova eccezione allora si cerca un altro handler in un blocco superiore <esp1> ed <esp2> devono avere lo stesso tipo
9

exception uno; exception due;

fun f(x)=if x=0 then raise uno else raise due;


fun g(y)= f (y) handle uno => 1;

g(0); ???? e

g(2) ????

e se avessimo: g(0) handle uno => 10; ???


10

le eccezioni possono servire anche a guadagnare efficienza: datatype a tree=Leaf a | Node a tree * a tree; fun prod(Leaf x) = x : int | prod(Node (x,y))=prod(x)*prod(y);

se si trova una foglia Leaf 0, inutile continuare

11

fun prod(T)= let exception Zero

fun p(Leaf x) = if x=0 then raise Zero


else x

| p(Node(x,y))= p(x)*p(y)
in

p(T) handle Zero => 0


end;

12

scope statico e scope dinamico:


val x=6; val w=let fun f(y)=x exception X; val w= let fun f(y)= raise X fun g(h)= h(1) handle X =>2 in let val x=4 in g(f) end end ; g(f) handle X => 4

fun g(h)= let val x=2


in h(1) end in

end handle X => 6;

statico
13

dinamico

val x=6;

1 [CL=0,AL=0,x=6] 2 [CL=0,AL=0,w=] 3[CL=2,AL=2, ris= (2)->w, ret= next, [3,f]], [3,g] ]

val w= let
fun f(y)=x fun g(h)= let val x=2 in h(1) end in let val x=4 in g(f) end

end ;

4[CL=3,AL=3, x=4] 5[CL=4,AL=3, ris=(2)->w, ret= h=[3,f], x=2, h(1)= ] 6[CL=5,AL=3, ris=(5)->h(1), ret= , y=1 ]

14

exception X;

val w= let
fun f(y)= raise X fun g(h) = h(1) handle X =>2 in g(f) handle X => 4

1[CL=0,AL=0, exc=X] 2[CL=1,AL=1, w= ] 3[CL=2,handle X => 6]

4[CL=3,AL=3,ris=(2)->w, ret=next , [4,f], [4,g] ]


5[CL=4,handle X => 4] 6[CL=5,AL=4, ris= (2)->w ret= let , h=[4,f], h(1)= ] 7[CL=6,handle X => 2]

end handle X => 6;

cosa succede veramente ?

8[CL=7,AL=4 ris=(6)->h(1), ret= in g , y=1]


15

eccezioni e de-allocazione della memoria

pila dei record di attivazione

heap

e se ?

16

exception X;

(let
val y=[1,2,3] in ..raise X end) handle X => il record dattivazione del let deallocato

quindi y viene tolto e la lista [1,2,3] sullo heap diventa inaccessibile: ci penser il garbage collector
17

nel C++ che non ha garbage collector la cosa pi seria


o lhandler pu comunque raggiungere i dati sullo heap oppure accettare il fenomeno: eccezioni sono eccezionali negli oggetti il distruttore viene invocato quando il record dattivazione che contiene loggetto viene deallocato stesso problema anche per altre risorse: per esempio i files
18

esame 21/6/2007
exception E of int; val x=1; val y=2; fun f(x)= if x <=0 then raise E(x) else x-y; val x=10; val y=20; fun h(a)= a(x) handle E(y) => f(x+y); val y=22; fun f(x)= if x=1 then x else raise E(y); val x=15; val y=25; val z= h(f);
19

1.fun f0()=raise X; 2.fun f1()=f0() handle X => raise X1(1); 3.fun f2()=f1() handle X1(x)=> raise X2(x+1); 4.fun f3()=f2() handle X2(x) =>x+1; val x=f3();

5 [CL=4,AL=4,x= ]

gestite da f3

6 [CL=5,AL=4,ris=(5)->x,rit=sist] 7 [CL=6, AL=6, handle X2(x) =>x+1, x= ] 8 [CL=7,AL=3,ris=(5)->x,rit=lab di f3] 9 [CL=8,AL=8,handle X1(x)=>raise X2(x+1), x=] 10 [CL=9,AL=2,ris=(5)->x,rit=lab di f2] 11 [CL=10,AL=10,handle X=>raise X1(1)] 12 [CL=11,AL=1,ris=(5)->x,rit=lab di f1]
20

f2 f1

1.fun f0()=raise X2(5); 2.fun f1()=f0() handle X => raise X1(1); 3.fun f2()=f1() handle X1(x)=> raise X2(x+1); 4.fun f3()=f2() handle X2(x) =>x+1; val x=f3();

5 [CL=4,AL=4,x= ]

gestite da f3

6 [CL=5,AL=4,ris=(5)->x,rit=sist] 7 [CL=6, AL=6, handle X2(x) =>x+1, x= ] 8 [CL=7,AL=3,ris=(5)->x,rit=lab di f3] 9 [CL=8,AL=8,handle X1(x)=>raise X2(x+1), x=] 10 [CL=9,AL=2,ris=(5)->x,rit=lab di f2] 11 [CL=10,AL=10,handle X=>raise X1(1)] 12 [CL=11,AL=1,ris=(5)->x,rit=lab di f1]
21

f2 f1

1.fun f0()=5; 2.fun f1()=f0() handle X => raise X1(1); 3.fun f2()=f1() handle X1(x)=> raise X2(x+1); 4.fun f3()=f2() handle X2(x) =>x+1; val x=f3();

5 [CL=4,AL=4,x= ]

gestite da f3

6 [CL=5,AL=4,ris=(5)->x,rit=sist] 7 [CL=6, AL=6, handle X2(x) =>x+1, x= ] 8 [CL=7,AL=3,ris=(5)->x,rit=lab di f3] 9 [CL=8,AL=8,handle X1(x)=>raise X2(x+1), x=] 10 [CL=9,AL=2,ris=(5)->x,rit=lab di f2] 11 [CL=10,AL=10,handle X=>raise X1(1)] 12 [CL=11,AL=1,ris=(5)->x,rit=lab di f1]
22

f2 f1

esercizio

exception A of int; exception E of int; val x=2; val w=1; val y=3; fun h(x)= if x=y then y else raise A(y); val y=4; fun f(w)= (if w=h(w) then raise E(w) else y) handle A(x)=> x; val x=f(y);

23

esercizio 8.1 exception Excpt of int; fun twice(f,x)=f(f(x)) handle Excpt(x) => x; fun pred(x)= if x=0 then raise Excpt(x) else x-1; fun dumb(x)= raise Excpt(x); fun smart(x)= 1+ pred(x) handle Excpt(x) => 1; twice(pred,1); twice(dumb,1); twice(smart, 0);

??

24

esercizio 8.4 fun f(0)= 1 | f(1)= raise Odd | f(3)= f(3-2) | f(n)= f(n-2) handle Odd =>~n; f(11) f(9) f(7) e poi?

25

esercizio 8.5 eccezioni e ricorsione terminale exception OddNum; fun f(0,count)= count | f(1,count)= raise OddNum | f(x,count)=f(x-2,count+1) handle OddNum => ~1 possiamo ottimizzare la ricorsione terminale ?

26

esercizio 8.6 eccezioni ed ordine di valutazione ricordate i linguaggi funzionali puri? In f(e1, e2) possiamo valutare e1 ed e2 in parallelo perch lordine di valutazione non importa ma se contengono raise ? exception A; exception B; fun f(0)= raise A | f(1)= raise B |f(x) =x; fun g(x,y)= x+y,
27

g(f(1),f(0)) handle A => 0 | B => 1;