Smalltalkではクラス変数はどこで定義されていますか?
たとえば、クラスの新しいクラス変数を定義する場合MyClass
、定義はに含まれるのでしょうか、MyClass
それともに含まれるのMyClass class
でしょうか。んMyClass class
でも、新しいクラス変数について知っていますか?
回答
はい、クラス変数はクラスおよびメタクラスと共有されます。また、すべてのサブクラス(およびそれらのメタクラス)と共有されます。クラス変数は通常大文字で表記され、クラスよりも広いスコープで共有されるという考えをより適切に伝えます。(メタクラスではなく)クラスでクラス変数を定義します。
クラス変数は、メタクラスレベルで定義されたインスタンス変数であるクラスインスタンス変数、つまりクラスオブジェクトのインスタンス変数と混同しないでください。この概念は、その単純さにもかかわらず(またはそのため)、ややあいまいです。インスタンス変数は、インスタンスの形状(スロット)を定義するために常にクラスで定義されます。したがって、この定義をクラスのクラスであるメタクラスに適用すると、ここで定義されたインスタンス変数は、そのインスタンスの形状を定義します。インスタンスの形状は、(通常は)1つだけです。
クラス変数に戻り、クラス(inst側)で定義し、メタクラス(つまり、クラス側)で初期化します。これらは、インスタンス、サブインスタンス、サブクラス、メタクラス間で共有されるという意味で(部分的な)グローバルであるため、グローバルを扱う通常の注意を払って処理する必要があることに注意してください。
もう1つの説明
インスタンス変数がインスタンスとサブインスタンス間で共有されると言うとき、それらの名前(およびオブジェクトスロットのメモリ内の位置)を意味します。それらの値(上記のスロットの内容)を意味するものではありません。したがって、クラスC
がcolor
ivarを定義している場合、クラスの2つのインスタンスは名前を共有color
しますが、各インスタンスでの値は独立しています。つまり、共有されるのは名前であり、値ではありません。
クラス変数で共有されるのは、名前と値の両方です。それは実際にはAssociation
オブジェクトであり、たとえばTheme -> aTheme
、共有されるものです。結果として、クラス変数の値を変更すると、そのすべての参照に影響します。クラスインスタンス変数は、通常のインスタンスやサブインスタンスではなく、クラスとそのサブクラスを形成することを除けば、インスタンス変数にすぎないため、これは当てはまりません。
Smalltalk変数の詳細については、を参照してください。 https://stackoverflow.com/a/42460583/4081336
Leandroの回答を補足するものとして、インスタンス側(クラス)とクラス側(メタクラス)の間でのクラス変数の共有を説明するSqueak実装固有のメインメソッドを次に示します。
Metaclass>>classPool
"Answer the dictionary of class variables."
^thisClass classPool
ここthisClass
で、はメタクラスの一意のインスタンス、つまりクラス自体です。
ただし、ほとんどのSmalltalk方言で同様の実装が見つかる可能性は高くなります。
コンパイラーは、最初に変数をメソッド/ブロック一時(methd / blockパラメーターを含む)として解決しようとし、次にインスタンス変数、次に共有変数として解決しようとします。
classPoolメソッドは、この最後のフェーズでコンパイラーによって送信されます。
Leandroは説明しました、コンパイラは、インスタンス変数スロットまたはメソッド一時変数の場合にバイトコードに直接転写されるオフセットとして、または共有変数の場合の一種の関連付けとしてバインディングを解決します。この関連付けは一般的にCompiledMethodリテラルに追加され、この変数を処理するすべてのメソッド間で効果的に共有されます(すべてのメソッドは、効果的に共有される同じAssocationオブジェクトを指します)。
コンパイラ部分ははるかに方言固有です。Squeakでは、共有変数のバインディングを解決するために使用されるのはこのメソッドです。
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
これは、Smalltalkの最も興味深い部分の1つは、IDE内から実装を掘り下げることができるということです。Smalltalkは基本的にSmalltalkで記述されています。