Dove sono definite le variabili di classe in Smalltalk?

Jan 19 2021

Mi chiedevo, se definisco una nuova variabile di classe, ad esempio per la classe MyClass, la definizione sarà in MyClasso in MyClass class? Fa MyClass classanche conoscere la nuova variabile di classe?

Risposte

5 LeandroCaniglia Jan 20 2021 at 00:36

Sì, le variabili di classe sono condivise con la classe e la metaclasse. Sono anche condivisi con tutte le sottoclassi (e le loro metaclassi). Una variabile di classe è solitamente in maiuscolo, per trasmettere meglio l'idea di essere condivisa in un ambito più ampio della classe. Si definiscono le variabili di classe nella classe (non la metaclasse).

Le variabili di classe non devono essere confuse con le variabili di istanza di classe, che sono variabili di istanza definite a livello di metaclasse, cioè variabili di istanza dell'oggetto classe. Questa nozione è alquanto oscura nonostante la sua semplicità (oa causa di essa): le variabili di istanza sono sempre definite nella classe per definire la forma (slot) delle sue istanze . Quindi, se applichiamo questa definizione alla metaclasse, che è la classe della classe, una variabile di istanza definita qui definisce la forma delle sue istanze, di cui ce n'è (di solito) solo una, la classe.

Tornando alle variabili di classe, le definisci nella classe (lato inst) e le inizializza nella metaclasse (cioè, lato classe). Ricorda che queste sono globali (parziali) nel senso che saranno condivise tra istanze, sostanze, sottoclassi e metaclassi e quindi devono essere gestite con la solita cura con cui trattiamo le globali.


Ancora una precisazione

Quando diciamo che le variabili di istanza sono condivise tra istanze e sostanze, intendiamo i loro nomi (e le posizioni nella memoria degli slot degli oggetti); non intendiamo i loro valori (contenuto di detti slot). Pertanto, due istanze della classe Ccondivideranno il nome, ad esempio color, se la classe definisce ivar color, ma i loro valori in ciascuna delle istanze saranno indipendenti. In altre parole, ciò che viene condiviso è il nome, non il valore.

Con le variabili di classe ciò che viene condiviso è sia il nome che il valore. In realtà è l' Associationoggetto, ad esempio Theme -> aTheme, ciò che è condiviso. Di conseguenza, qualsiasi modifica al valore di una variabile di classe influisce su tutti i suoi riferimenti. Questo non è il caso delle variabili di istanza di classe perché non sono altro che variabili di istanza, eccetto che modellano la classe e le sue sottoclassi, piuttosto che istanze e sostanze regolari.


Per ulteriori informazioni sulle variabili Smalltalk, vedere https://stackoverflow.com/a/42460583/4081336

2 aka.nice Jan 20 2021 at 23:59

Proprio come complemento alla risposta di Leandro, ecco il principale metodo specifico per l'implementazione di Squeak che spiega la condivisione delle variabili di classe tra il lato istanza (classe) e il lato classe (metaclasse):

Metaclass>>classPool
    "Answer the dictionary of class variables."

    ^thisClass classPool

dov'è thisClassl'istanza unica della Metaclass, ovvero la classe stessa ...

Tuttavia, ci sono alte possibilità di trovare un'implementazione simile nella maggior parte dei dialetti Smalltalk.

Il compilatore proverà prima a risolvere la variabile come metodo / blocco temporaneo (inclusi parametri methd / blocco), quindi variabili di istanza, quindi variabili condivise.

Il metodo classPool viene inviato dal compilatore in quest'ultima fase.

Un Leandro ha spiegato, il compilatore risolve il binding proprio come un offset che verrà trascritto direttamente nel bytecode in caso di slot della variabile di istanza o variabile temporanea del metodo, o come una sorta di associazione per il caso della variabile condivisa, questa associazione è generalmente aggiunto ai valori letterali CompiledMethod ed effettivamente condiviso tra tutti i metodi che si occupano di questa variabile (tutti i metodi puntano allo stesso oggetto Assocation che è effettivamente condiviso).

La parte del compilatore è molto più specifica del dialetto, in Squeak, è questo metodo che viene utilizzato per risolvere l'associazione di variabili condivise:

class>>bindingOf: varName environment: anEnvironment
    "Answer the binding of some variable resolved in the scope of the receiver"
    | aSymbol binding |
    aSymbol := varName asSymbol.

    "First look in local classVar dictionary."
    binding := self classPool bindingOf: aSymbol.
    binding ifNotNil:[^binding].

    "Next look in local shared pools."
    self sharedPools do:[:pool | 
        binding := pool bindingOf: aSymbol.
        binding ifNotNil:[^binding].
    ].

    "Next look into superclass pools"
    superclass ifNotNil: [^ superclass bindingOf: aSymbol environment: anEnvironment].

    "No more superclass... Last look in declared environment."
    ^anEnvironment bindingOf: aSymbol

Questo per ricordarti che una delle parti più interessanti di Smalltalk è che puoi scavare nell'implementazione dall'IDE, Smalltalk è essenzialmente scritto in Smalltalk!