33de0609415469365be6efd3d4290da584401ce5
linguaggi/s02/sottoprogrammi_ed_eccezioni.md
| ... | ... | @@ -0,0 +1,289 @@ |
| 1 | +# Sottoprogrammi |
|
| 2 | + |
|
| 3 | +Un linguaggio senza parametri puo'esistere? Si (es. assembly) |
|
| 4 | + |
|
| 5 | +## Astrazione |
|
| 6 | + |
|
| 7 | +- identificare proprietà importanti di cosa si vuole descrivere |
|
| 8 | +- concentrarsi sulle questioni rilevanti e ignorare le altre |
|
| 9 | +- cosa è rilevante dipende dallo scopo del progetto |
|
| 10 | + |
|
| 11 | +Voglio asseganare a un gruppo di istruzioni un nome e fare fare a questo gruppo di istruzioni delle op su dei paramentri che passo. Il codice diventa piu astratto e piu leggibile |
|
| 12 | + |
|
| 13 | +Nota: I LP sono essi stessi astrazioni del calcolatore sottostante |
|
| 14 | + |
|
| 15 | +Astrazione sul controllo e sui dati |
|
| 16 | + |
|
| 17 | +### Astrazione sul controllo |
|
| 18 | + |
|
| 19 | +Sono per es: sottoprogrammi, blocchi, parametri |
|
| 20 | + |
|
| 21 | +``` |
|
| 22 | +double P (int x) { |
|
| 23 | + double z; |
|
| 24 | + /* CORPO DELLA FUNZIONE |
|
| 25 | + return expr; |
|
| 26 | +} |
|
| 27 | +``` |
|
| 28 | + |
|
| 29 | + |
|
| 30 | + |
|
| 31 | +### Astrazione del controllo |
|
| 32 | + |
|
| 33 | +Fornisce astrazione funzionale al progetto: |
|
| 34 | + |
|
| 35 | +- ogni componente fornisce servizi al suo ambiente |
|
| 36 | +- la sua astrazione descrive il comportamente esterno |
|
| 37 | +- e nasconde i dettagli interni necessari a produrlo |
|
| 38 | + |
|
| 39 | +Interazione limitata al comportamento esterno |
|
| 40 | + |
|
| 41 | +Comunicazione attraverso: |
|
| 42 | + |
|
| 43 | +- parametri |
|
| 44 | +- ambiente globale (ma distrugge l’astrazione) |
|
| 45 | + |
|
| 46 | +### Astrazione sui dati |
|
| 47 | + |
|
| 48 | +Tipo di dato = valori e operazioni (`integer = [-maxint..maxint]` e ` {+,-,*,div,mod}`) |
|
| 49 | +La rappresentazione (implementazione) dei dati delle operazioni inaccessibile all’utente, perché protetta da una capsula che la isola |
|
| 50 | + |
|
| 51 | +> Nota: impossibile nel linguaggi più vecchi |
|
| 52 | +> |
|
| 53 | +> - FORTRAN, Pascal, C |
|
| 54 | + |
|
| 55 | +### Parametri |
|
| 56 | + |
|
| 57 | +Terminologia |
|
| 58 | + |
|
| 59 | +- dichiarazione/definizione `int f (int n) {return n+1}` n si dice parametro formale |
|
| 60 | +  |
|
| 61 | + |
|
| 62 | +Nota: Una funz comunica con il chiamante (return) |
|
| 63 | + |
|
| 64 | +#### Modalita' di passaggio dei parametri |
|
| 65 | + |
|
| 66 | +Per valore: |
|
| 67 | + |
|
| 68 | +- il val dell'attuale e'assegnato al formale, che si comporta come una var locale |
|
| 69 | +- pragmatica: main -> proc |
|
| 70 | +- attuale qualsiasi; modifiche al formale non passano all'attuale |
|
| 71 | + |
|
| 72 | +Per riferimento: |
|
| 73 | + |
|
| 74 | +- viene passato un riferimento (indirizzo) all'attuale; i riferimenti al formale sono referimenti all'attuale (aliasing) |
|
| 75 | +- pragmatica: main <-> proc |
|
| 76 | +- attuale: variabile; modifiche al formale passano all'attuale |
|
| 77 | + |
|
| 78 | +##### Es passaggio per valore: |
|
| 79 | + |
|
| 80 | +```c |
|
| 81 | +void foo (int x) { x = x+1; } |
|
| 82 | + … |
|
| 83 | + y = 1; |
|
| 84 | + foo(y+1); |
|
| 85 | +``` |
|
| 86 | + |
|
| 87 | +dopo foo y vale comunque 1. |
|
| 88 | + |
|
| 89 | +- Il formale x è una var locale (sulla pila) |
|
| 90 | +- Alla chiamata, l’attuale y+1 è valutato ed il valore è assegnato al formale x |
|
| 91 | +- Nessun legame tra x nel corpo di foo e y nel chiamante |
|
| 92 | +- Al ritorno da foo, x viene distrutto (tolto dalla pila) |
|
| 93 | +- Non è possibile trasmettere info da foo al chiamante mediante il parametro |
|
| 94 | +- Costoso per dati grandi: copia |
|
| 95 | +- Java, Scheme, Pascal (default), C e Java (unico modo); |
|
| 96 | + |
|
| 97 | +##### Es: passaggio per riferimento |
|
| 98 | + |
|
| 99 | +```c |
|
| 100 | +void foo (reference int x){ x = x+1;} |
|
| 101 | + … |
|
| 102 | + y = 1; |
|
| 103 | + foo(y); |
|
| 104 | +``` |
|
| 105 | + |
|
| 106 | +dopo foo y vale 2. |
|
| 107 | + |
|
| 108 | +- viene passato un riferimento (indirizzo; puntatore) |
|
| 109 | +- Il formale x è un alias di y |
|
| 110 | +- L’attuale deve essere un L-valore (“una variabile”) |
|
| 111 | +- Al ritorno da foo, viene distrutto il (solo) legame tra x e l’indirizzo di y |
|
| 112 | +- Trasmissione bidirezionale tra chiamante e chiamato |
|
| 113 | +- Efficiente nel passaggio, ma indirezione nel corpo |
|
| 114 | +- Pascal (var); in C simulato passando un puntatore… |
|
| 115 | + |
|
| 116 | +### Passaggio per risultato: |
|
| 117 | + |
|
| 118 | +simile al passaggio per riferimento. |
|
| 119 | + |
|
| 120 | +```c |
|
| 121 | +void foo (result int x) {x = 8;} |
|
| 122 | + … |
|
| 123 | + y = 1; |
|
| 124 | + foo(y); |
|
| 125 | +``` |
|
| 126 | + |
|
| 127 | +- Il formale x è una var locale (sulla pila) |
|
| 128 | +- Al ritorno da foo, il valore di x è assegnato all’attuale y |
|
| 129 | +- Nessun legame tra x nel corpo di foo e y nel chiamante |
|
| 130 | +- Al ritorno da foo, x viene distrutto (tolto dalla pila) |
|
| 131 | +- Non è possibile trasmettere info dal chiamante a foo mediante il parametro |
|
| 132 | +- Costoso per dati grandi: copia |
|
| 133 | +- Ada: out |
|
| 134 | + |
|
| 135 | +### Passaggio per valore/risultato: |
|
| 136 | + |
|
| 137 | +Insieme valore+risultato. |
|
| 138 | +Pragmatica: main ↔ proc |
|
| 139 | + |
|
| 140 | +Esiste(-va) in Algol-W: |
|
| 141 | +void foo (value-result int x) |
|
| 142 | +{ x = x+1; } |
|
| 143 | +… |
|
| 144 | +y = 8; |
|
| 145 | +foo(y); |
|
| 146 | +qui y vale 9 |
|
| 147 | +• Il formale x è a tutti gli effetti una var locale (sulla pila) |
|
| 148 | +• Alla chiamata, il valore dell’attuale è assegnato al formale |
|
| 149 | +• Al ritorno, il valore del formale è assegnato all’attuale |
|
| 150 | +• Nessun legame tra x nel corpo di foo e y nel chiamante |
|
| 151 | +• Al ritorno da foo, x viene distrutto (tolto dalla pila) |
|
| 152 | +• Costoso per dati grandi: copia |
|
| 153 | +• Ada: in out (ma solo per dati piccoli; per dati grandi passa riferimento) |
|
| 154 | + |
|
| 155 | +### Valore e riferimento: morale |
|
| 156 | + |
|
| 157 | +Passaggio per valore: |
|
| 158 | +• semantica semplice: il corpo non ha necessità di conoscere come la procedura verrà chiamata (trasparenza referenziale) |
|
| 159 | +• implementazione abbastanza semplice |
|
| 160 | +• potenzialmente costoso il passaggio; efficiente il riferimento al parametro formale |
|
| 161 | +• necessità di altri meccanismi per comunicare main ← proc |
|
| 162 | +• Passaggio per riferimento: |
|
| 163 | +• semantica complessa; aliasing |
|
| 164 | +• implementazione semplice |
|
| 165 | +• efficiente il passaggio; un po’ più costoso il riferimento al parametro formale (un indiretto) |
|
| 166 | + |
|
| 167 | +### Valore, e non riferimento |
|
| 168 | + |
|
| 169 | +I vantaggi del passaggio per valore: |
|
| 170 | + |
|
| 171 | +- in particolare la trasparenza referenziale suggeriscono linguaggi con passaggio solo per valore |
|
| 172 | + più meccanismi separati per ottenere il passaggio per |
|
| 173 | + riferimento: |
|
| 174 | + puntatori in C |
|
| 175 | + variabili in modello a riferimento (tipi classe) in Jav |
|
| 176 | + |
|
| 177 | +### Passaggio per nome |
|
| 178 | + |
|
| 179 | +Regole di copia: |
|
| 180 | + |
|
| 181 | +- una chiamata alla procedura P e' la stessa cosa che eseguire il corpo di P dopo aver sostituito i parametri attuali al posto dei parametri formali |
|
| 182 | + |
|
| 183 | +La macro espansione viene realizzata in modo semanticamente corretto |
|
| 184 | +In algol-w era il default: |
|
| 185 | + |
|
| 186 | +```algol |
|
| 187 | + |
|
| 188 | +int y; |
|
| 189 | +void foo (name int x) {x= x + 1; } |
|
| 190 | +… |
|
| 191 | +y = 1; |
|
| 192 | +foo(y); |
|
| 193 | +``` |
|
| 194 | + |
|
| 195 | +foo esegue `y=y+1` |
|
| 196 | + |
|
| 197 | +Caso piu complicato |
|
| 198 | + |
|
| 199 | +conflitto di variabili! |
|
| 200 | +Le due variabili `y` e `y` rossa sono diverse. fie incrementa l'attuale (y) attraverso il formale x e crea e distrugge la nuova y rossa |
|
| 201 | + |
|
| 202 | +Soluzione: |
|
| 203 | +Viene passata una coppia: `<exp, amb>` |
|
| 204 | +• `exp` è il parametro attuale (testo, non valutato) |
|
| 205 | +• `amb` è l’ambiente di valutazione (in scoping statico) |
|
| 206 | +• Ogni volta che il formale è usato, `exp` è valutata in `amb` |
|
| 207 | + |
|
| 208 | + |
|
| 209 | + |
|
| 210 | +Altro esempio: |
|
| 211 | + |
|
| 212 | +```java |
|
| 213 | +void fie (int x, int y) { |
|
| 214 | + x = x+1; |
|
| 215 | + y = 1;} |
|
| 216 | +… |
|
| 217 | +int i = 1; |
|
| 218 | +int[] A = new int[5]; |
|
| 219 | +A[1]=4; |
|
| 220 | +fie (i,A[i]); |
|
| 221 | +``` |
|
| 222 | + |
|
| 223 | + |
|
| 224 | +Passaggio per nome |
|
| 225 | +il corpo della proc viene riscritto al posto della chiamata e sostituisco le var con quelle in input |
|
| 226 | + |
|
| 227 | +La i e `A[i]` sono valutate nel main (il loro amb) |
|
| 228 | + |
|
| 229 | +quand arrivo al punto A[i] (ovvero y) = 1 visto che prima i e' stato incrementato allora andro' a modificare anche la i di A[i] quindi diventa A[2] = 1 |
|
| 230 | + |
|
| 231 | +``` |
|
| 232 | +f(nome x) |
|
| 233 | + y = x |
|
| 234 | + y = x |
|
| 235 | + y = x |
|
| 236 | + |
|
| 237 | +z = 1 |
|
| 238 | +f(z++) |
|
| 239 | +``` |
|
| 240 | + |
|
| 241 | +con passaggio per nome la sostituzione viene fatta ogni volta che viene trovato il param corrispondente |
|
| 242 | + |
|
| 243 | +quindi diventa: |
|
| 244 | + |
|
| 245 | +``` |
|
| 246 | +f(nome x) |
|
| 247 | + y = z++ |
|
| 248 | + y = z++ |
|
| 249 | + y = z++ |
|
| 250 | + |
|
| 251 | +z = 1 |
|
| 252 | +f(z++) |
|
| 253 | +``` |
|
| 254 | + |
|
| 255 | +quindi y diventa 4 (o 3, in base a quando viene fatto z++) |
|
| 256 | + |
|
| 257 | +#### Implementazione passaggio per nome |
|
| 258 | + |
|
| 259 | +Come passare la coppia <exp,env>? |
|
| 260 | +– un puntatore al testo di exp |
|
| 261 | +– un puntatore di catena statica (sullo stack) al record di |
|
| 262 | +attivazione del blocco di chiamata |
|
| 263 | + |
|
| 264 | +cioè una chiusura (perché chiude un’espressione: elimina le sue variabili libere legandole nell’ ambiente del chiamante) |
|
| 265 | + |
|
| 266 | +Le chiusure servono a passare funzioni come argomenti ad altre |
|
| 267 | +procedure |
|
| 268 | +Parametro per nome = funzione nascosta senza argomenti che valuta il parametro nell’ambiente del chiamante (un thunk, nel gergo Algol) |
|
| 269 | + |
|
| 270 | + |
|
| 271 | + |
|
| 272 | +### Funzioni di ordine superiore |
|
| 273 | + |
|
| 274 | +Alcuni linguaggi permettono di: |
|
| 275 | +– passare funzioni come argomenti di procedure |
|
| 276 | +– restituire funzioni come risultato di procedure |
|
| 277 | +• Entrambi i casi: come gestire l’ambiente della funzione ? |
|
| 278 | +• Caso più semplice |
|
| 279 | +– Funzioni come argomento |
|
| 280 | +– Occorre un puntatore al record di attivazione all’interno della pila: passa una chiusura ! |
|
| 281 | +• Caso più complicato |
|
| 282 | +– Funzione restituita da una chiamata di procedura |
|
| 283 | +– Occorre mantenere il record di attivazione della funzione |
|
| 284 | +restituita: disciplina a pila non funziona!! |
|
| 285 | + |
|
| 286 | + |
|
| 287 | + |
|
| 288 | +in scope dinamico la x dentro la f puo velere 7 (se pero si valuta lo scope di f quando viene chiamata e non quando viene passata) quindi guardo il suo ambiente quando viene chiamata non passata. Questa regola si chiama regola di shallow binding |
|
| 289 | +Altrimenti (nel caso in cui io valuti l'ambiente della funz quando essa viene passata e non quand o viene chiamata), ovvero alla riga `g(f)` quindi la x vale 5. Questa regola si chiama deep binding |