I frame di stack sono usati per memorizzare variabili locali (variabili dichiarate all'interno di una funzione). In molte lingue, non è significativo parlare del "nome completo" di una variabile locale.
Al contrario, namespace, pacchetti o moduli vengono utilizzati per organizzare i simboli globali. Questi simboli possono fare riferimento a funzioni di livello superiore o variabili globali oa concetti che non sono rappresentati direttamente nella memoria. Gli accessi a questi simboli non vengono quindi compilati in quanto la memoria viene letta in relazione al puntatore dello stack.
È anche importante notare che i frame stack non contengono il nome dei simboli che contengono. Se un frame dello stack "memorizza una variabile x
", significa semplicemente che riserva memoria a un offset di puntatore dello stack noto in fase di compilazione per il valore di tale variabile. Poiché tutti gli accessi sono eseguiti tramite l'offset e non il nome, il nome è sconosciuto in fase di esecuzione (a meno che non si compili con i simboli di debug attivati).
Con le funzioni annidate, potremmo voler fare riferimento ai simboli di una funzione di inclusione, ad es.
function f(x) {
return function g(y) { return x + y; }
}
Qui, all'interno g()
il simbolo x
fa riferimento all'ambito esterno. Questo può essere fatto con link statici: c'è un puntatore dal frame dello stack di g()
allo stack frame di f()
. In pseudo-C, y
verrebbe compilato come stack_frame->y
, ma x
come stack_frame->enclosing_scope->x
.
La parte difficile con le funzioni annidate non sta attraversando la catena di ambito, ma assicurandosi che tutti gli ambiti accessibili durino quanto ogni riferimento a una funzione nidificata. Se un riferimento a una funzione nidificata può lasciare la funzione di inclusione, questo implica necessariamente la garbage collection.
Se l'ambito che racchiude ha una variabile con lo stesso nome di un ambito interno, l'ambito interno ombreggia la variabile esterna:
function f(x) {
return function g(x) { return x; } // x always refers to g()'s x
}
Nella maggior parte delle lingue, la variabile f()
di x
è completamente inaccessibile da g()
. Eccezioni alla regola:
-
Il nonlocal
di Python è simile, ma in realtà si limita ad aliasare una variabile esterna nello scope nidificato. Non consente di disambiguare le variabili interne e quelle ombreggiate.
-
Lo pseudo-namespace% perOUTER
di Perl6 ci consente di accedere alle variabili ombreggiate:
my $x = 5;
{
my $x = 6;
say $x; #=> 6
say $OUTER::x #=> 5
}
Lo spazio dei nomi OUTER
non è uno spazio dei nomi globale, ma piuttosto un modo per aumentare il processo di ricerca delle variabili.