errors
Failed to load YAML frontmatter: Tried to load unspecified class: Time

Variabili

L’ambiente (in uno specifico blocco) può essere suddiviso in:

  • Ambiente locale: associazioni create all’ingresso nel blocco (es. variabili locali, parametri formali).
  • Ambiente non locale: associazioni ereditate da altri blocchi.
  • Ambiente globale: la parte di ambiente non locale relativa alle associazioni comuni a tutti i blocchi (es. dichiarazioni esplicite di variabili globali, dichiarazioni del blocco più esterno, associazioni esportate da moduli).

Operazioni sugli oggetti denotabili

Le operazioni fondamentali che si possono compiere su un oggetto sono:

  • Creazione
  • Accesso
  • Modifica (se l’oggetto è modificabile)
  • Distruzione

Nota Bene: Creazione e distruzione di un oggetto non coincidono necessariamente con la creazione e distruzione dei legami per quell'oggetto.

Eventi fondamentali nel ciclo di vita

  1. Creazione di un oggetto
  2. Creazione di un legame per l’oggetto
  3. Riferimento all’oggetto (tramite il legame)
  4. Disattivazione di un legame
  5. Riattivazione di un legame
  6. Distruzione di un legame
  7. Distruzione di un oggetto
  • Tempo di vita dell'oggetto (Lifetime): Il tempo trascorso tra i punti 1 e 7.
  • Tempo di vita dell'associazione (Legame): Il tempo trascorso tra i punti 2 e 6.

Nota: La vita di un oggetto non coincide con la vita dei legami per quell’oggetto • Vita dell’oggetto più lunga di quella del legame:(variabile passata ad una proc per riferimento)

procedure P (var X:integer); begin… end;
…
var A:integer;
…
P(A);

Area di memoria allocata dinamicamente (es. puntatori in C):

int *X, *Y;
…
X = (int *) malloc (sizeof (int));
Y=X;
…
free (X);
X=null;

Scope (visibilità)

Una dichiarazione locale ad un blocco è visibile in quel blocco e in tutti i blocchi in esso annidati, a meno che non intervenga in tali blocchi una nuova dichiarazione dello stesso nome (che nasconde, o maschera, la precedente)

Il problema della risoluzione di un riferimento non locale nasce in presenza di:

  • Procedure (ovvero blocchi eseguiti in posizioni diverse dalla loro definizione).
  • Ambiente non locale (e non globale).
{
    int x = 10;

    void foo() {
        x++;
    }

    void fie() {
        int x = 0;
        foo();
    }

    fie();
}

Quale x viene incrementata da foo? La risposta dipende dalla regola di scope adottata dal linguaggio:

  • Scope Statico: Il riferimento è risolto nel blocco che include sintatticamente B.
  • Scope Dinamico: Il riferimento è risolto nel blocco che è stato eseguito immediatamente prima di B.

Esempi di Output a confronto

Con Scope Statico: Il riferimento è legato alla struttura del testo. la chiamata di pippo usa sempre la x definita al suo stesso livello.

{int x = 0;
void pippo(int n){
    x = n+1;
}
pippo(3);
write(x); # stampa 4
{
int x = 0;
pippo(3);
write(x); # stampa 0
}
write(x); # stampa 4

Con Scope Dinamico: Un nome non locale è risolto nel blocco attivato più di recente e non ancora disattivato. pippo usa la x del chiamante.

{int x = 0;
void pippo(int n){
    x = n+1;
}
pippo(3);
write(x); # stampa 4
{
int x = 0;
pippo(3);
write(x); # stampa 4
}
write(x); # stampa 4

I principi dello Scope Statico

Lo scope statico si basa su due principi fondamentali: 1. Indipendenza dalla posizione: Il corpo di foo è parte dello scope della x più esterna. L'unico modo in cui foo può essere compilata in modo univoco è che il riferimento a x sia sempre quello più esterno, indipendentemente da dove foo venga chiamata.

{int x = 10;
void foo(){
    x++;
}
void fie (){
    int x = 0;
    foo();
}
fie();
foo();
}

2. Indipendenza dai nomi locali: La modifica del nome di una variabile locale in un blocco chiamante non deve influire sulla funzione chiamata.

{int x = 10;
void foo(){
    x++;
}
void fie (){
    int y = 0;
    foo();
}
fie();
foo();
}

Rinominare la locale da x a y dentro fie:

  • Modifica la semantica del programma in scope dinamico.
  • Non ha alcun effetto in scope statico.

Nota sullo scope dinamico: È utile per "specializzare" una funzione a runtime. Ad esempio, una procedura visualizza che renderizza a video può ereditare il colore rosso semplicemente definendo una variabile locale prima di chiamarla:

{var colore = rosso;
visualizza(testo);}

Confronto: Statico vs Dinamico

Scope Statico:

  • Informazione completa dal testo del programma.
  • Le associazioni sono note a tempo di compilazione.
  • Garantisce i principi di indipendenza.
  • Concettualmente più complesso da implementare nel compilatore, ma più efficiente a runtime.
  • Linguaggi: Algol, Pascal, C, Java, Ada.

Scope Dinamico:

  • Informazione derivata dall'esecuzione.
  • Spesso causa di programmi meno "leggibili" e più difficili da debuggare.
  • Concettualmente più semplice da implementare, ma meno efficiente.
  • Linguaggi: Lisp (alcune versioni), Perl.

Approfondimento: Le differenze emergono solo in presenza congiunta di ambiente non locale (e non globale) e procedure. Algol, Pascal, Ada e Java permettono di annidare blocchi di sottoprogrammi, cosa non possibile in C. Questo non vuol dire che la regola di scoping sia indifferente in C, le regole si applicano ugualmente a contesti globali/locali!

Determinare l'ambiente

L'ambiente è dunque determinato da:

  • Regola di scope (dinamico o statico).
  • Regole specifiche del linguaggio (es. obbligo di dichiarare la variabile prima di assegnarla).!

Determinare l'ambiente

L'ambiente e' dunque determinato da:

  • regola di scope (dinamico o statico)
  • regole specifiche (es. dichiarare la variabile prima di assegnarla)

Gestione della memoria

Statica a pila, con heap. Implementazione delle regole di scope.

Tipi di allocazione della memoria vita di un oggetto corrisponde (in genere) con tre meccanismi di allocazione di memoria:

  • statica: memoria allocata a tempo di compilazione (es. variabili globali)
  • dinamica: memoria allocata a tempo di esecuzione (pila, heap)

Allocazione statica

Un oggetto ha un indirizzo assoluto che è mantenuto per tutta l’esecuzione del programma Solitamente sono allocati staticamente: – variabili globali – variabili locali sottoprogrammi (senza ricorsione) – costanti determinabili a tempo di compilazione – tabelle usate dal supporto a run-time

Spesso usate zone protette di memoria

Nota:E invece se devo assegnare staticamente mem a una funz quanta mem assegno?

un programma con 3 funz da 1k di mem

quanta mem alloco? 3k? 1k? Devo vedere quante chiamate alle funz ho (1 chiamata = 1k mem occupata) Se c'e ricorsione e' un casino -> non posso determinare prima quanta mem allocare quindi per permettere la ricorsione devo usare allocazione dinamica della mem. Es. FORTRAN: non ammette la ricorsione 20260219_2026-02-19_14-43-50

20260219_2026-02-19_14-40-34