Gdzie są zdefiniowane zmienne klasowe w Smalltalk?

Jan 19 2021

Zastanawiałem się, czy jeśli zdefiniuję nową zmienną klasy, na przykład dla klasy MyClass, czy definicja będzie w, MyClassczy w MyClass class? Czy w MyClass classogóle wie o nowej zmiennej klasy?

Odpowiedzi

5 LeandroCaniglia Jan 20 2021 at 00:36

Tak, zmienne klas są współdzielone z klasą i metaklasą. Są również współdzielone ze wszystkimi podklasami (i ich metaklasami). Zmienna klasy jest zwykle pisana wielką literą, aby lepiej przekazać ideę współdzielenia w zakresie szerszym niż klasa. Definiujesz zmienne klasowe w klasie (nie w metaklasie).

Zmiennych klas nie należy mylić ze zmiennymi instancji klas, które są zmiennymi instancji zdefiniowanymi na poziomie metaklasy, tj. Zmiennymi instancji obiektu klasy. To pojęcie jest nieco niejasne pomimo swojej prostoty (lub z tego powodu): zmienne instancji są zawsze definiowane w klasie, aby zdefiniować kształt (szczeliny) jej instancji . Jeśli więc zastosujemy tę definicję do metaklasy, która jest klasą klasy, to zdefiniowana tutaj zmienna instancji definiuje kształt jej instancji, z których jest (zwykle) tylko jedna, klasa.

Wracając do zmiennych klas, definiujesz je w klasie (po stronie inst) i inicjalizujesz w metaklasie (tj. Po stronie klasy). Pamiętaj, że są to (częściowe) wartości globalne w tym sensie, że będą one współdzielone między instancjami, substancjami, podklasami i metaklasami, dlatego należy się z nimi obchodzić ze zwykłą ostrożnością, z jaką traktujemy elementy globalne.


Jeszcze jedno wyjaśnienie

Kiedy mówimy, że zmienne instancji są wspólne dla instancji i substancji, mamy na myśli ich nazwy (i pozycje w pamięci gniazd obiektów); nie mamy na myśli ich wartości (zawartości wspomnianych slotów). Zatem dwie instancje klasy Cbędą miały wspólną nazwę, powiedzmy color, jeśli klasa definiuje ivar color, ale ich wartości w każdej z instancji będą niezależne. Innymi słowy, udostępniana jest nazwa, a nie wartość.

W przypadku zmiennych klasowych to, co jest wspólne, to zarówno nazwa, jak i wartość. W rzeczywistości jest to Associationobiekt, na przykład Theme -> aThemeto, co jest udostępniane. W konsekwencji każda modyfikacja wartości zmiennej klasy wpływa na wszystkie jej odwołania. Nie dotyczy to zmiennych instancji klas, ponieważ są one niczym innym jak zmiennymi instancji, z wyjątkiem tego, że kształtują klasę i jej podklasy, a nie zwykłe instancje i substancje.


Aby uzyskać więcej informacji na temat zmiennych Smalltalk, zobacz https://stackoverflow.com/a/42460583/4081336

2 aka.nice Jan 20 2021 at 23:59

Jako uzupełnienie odpowiedzi Leandro, oto główna metoda specyficzna dla implementacji Squeak, która wyjaśnia współdzielenie zmiennych klas między stroną instancji (klasa) i stroną klasy (metaklasa):

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

    ^thisClass classPool

gdzie thisClassjest unikalna instancja Metaclass, czyli sama klasa ...

Istnieją jednak duże szanse na znalezienie podobnej implementacji w większości dialektów Smalltalk.

Kompilator najpierw spróbuje rozwiązać zmienną jako tymczasową metodę / blok (w tym parametry metody / bloku), następnie zmienne instancji, a następnie zmienne współdzielone.

Metoda classPool jest wysyłana przez kompilator w tej ostatniej fazie.

Leandro wyjaśnił, że kompilator albo rozwiązuje powiązanie jako przesunięcie, które zostanie bezpośrednio transkryptowane w kodzie bajtowym w przypadku zmiennej instancji slot lub tymczasowej zmiennej metody, albo jako rodzaj skojarzenia dla przypadku zmiennej współdzielonej, to skojarzenie jest generalnie dodane do literałów CompiledMethod i efektywnie współużytkowane przez wszystkie metody zajmujące się tą zmienną (wszystkie metody wskazują na ten sam obiekt Assocation, który jest efektywnie współużytkowany).

Część kompilatora jest znacznie bardziej specyficzna dla dialektu, w Squeak jest to ta metoda, która jest używana do rozwiązywania powiązań współdzielonych zmiennych:

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

Ma to na celu przypomnienie, że jedną z najciekawszych części Smalltalk jest to, że możesz zagłębić się w implementację z poziomu IDE, Smalltalk jest zasadniczo napisany w Smalltalk!