Smalltalk'ta sınıf değişkenleri nerede tanımlanır?
Merak ediyordum, örneğin sınıf için yeni bir sınıf değişkeni MyClass
tanımlarsam, tanım MyClass
içinde MyClass class
mi yoksa içinde mi olacak ? MyClass class
Yeni sınıf değişkenini bile biliyor mu ?
Yanıtlar
Evet, sınıf değişkenleri sınıf ve meta sınıfla paylaşılır. Ayrıca tüm alt sınıflarla (ve meta sınıflarıyla) paylaşılırlar. Bir sınıf değişkeni, sınıftan daha geniş bir kapsamda paylaşılma fikrini daha iyi iletmek için genellikle büyük harfle yazılır. Sınıf değişkenlerini sınıfta tanımlarsınız (meta sınıfta değil).
Sınıf değişkenleri, meta sınıf düzeyinde tanımlanan örnek değişkenleri olan sınıf örneği değişkenleriyle, yani sınıf nesnesinin örnek değişkenleriyle karıştırılmamalıdır. Bu kavram, basitliğine (veya bu nedenle) rağmen biraz belirsizdir: örnek değişkenleri, örneklerinin şeklini (yuvalarını) tanımlamak için her zaman sınıfta tanımlanır . Bu nedenle, bu tanımı sınıfın sınıfı olan meta sınıfa uygularsak, burada tanımlanan bir örnek değişkeni, (genellikle) yalnızca bir sınıf olan örneklerinin şeklini tanımlar.
Sınıf değişkenlerine geri dönersek, onları sınıfta (inst tarafında) tanımlar ve metasınıfta (yani, sınıf tarafında) başlatırsınız. Bunların örnekler, alt sınıflar, alt sınıflar ve meta sınıflar arasında paylaşılacak (kısmi) küreseller olduğunu ve bu nedenle küresellere uyguladığımız olağan özenle ele alınmaları gerektiğini unutmayın.
Bir açıklama daha
Örnek değişkenlerinin örnekler ve alt örnekler arasında paylaşıldığını söylediğimizde, adlarını (ve nesne yuvalarının belleğindeki konumlarını) kastediyoruz; değerlerini kastetmiyoruz (söz konusu yuvaların içerikleri). Bu nedenle, örneğin sınıf ivar'ı tanımlıyorsa, sınıfın iki örneği C
adı paylaşacaktır , ancak bunların her bir color
örnekteki color
değerleri bağımsız olacaktır. Başka bir deyişle, paylaşılan şey değer değil, addır.
Sınıf değişkenleriyle paylaşılan, hem ad hem de değerdir. Aslında Association
nesnedir, örneğin Theme -> aTheme
paylaşılan şeydir. Sonuç olarak, bir sınıf değişkeninin değerinde yapılan herhangi bir değişiklik tüm referanslarını etkiler. Sınıf örneği değişkenlerinde durum böyle değildir çünkü bunlar, normal örnekler ve alt örneklerden ziyade sınıfı ve alt sınıflarını şekillendirmeleri dışında örnek değişkenlerinden başka bir şey değildirler.
Smalltalk değişkenleri hakkında daha fazla bilgi için bkz. https://stackoverflow.com/a/42460583/4081336
Leandro'nun cevabının bir tamamlayıcısı olarak, örnek tarafı (sınıf) ve sınıf tarafı (metasınıf) arasında sınıf değişkenlerinin paylaşımını açıklayan ana Squeak uygulamasına özgü yöntemi burada bulabilirsiniz:
Metaclass>>classPool
"Answer the dictionary of class variables."
^thisClass classPool
thisClass
Metaclass'ın benzersiz örneği nerede , yani sınıfın kendisi ...
Çoğu Smalltalk lehçesinde benzer uygulama bulma şansı yüksektir.
Derleyici önce değişkeni bir yöntem / blok geçici olarak (methd / blok parametreleri dahil), ardından örnek değişkenleri, sonra paylaşılan değişkenler olarak çözmeye çalışacaktır.
ClassPool yöntemi bu son aşamada derleyici tarafından gönderilir.
Bir Leandro açıkladı, derleyici ya bağlamayı, örnek değişkeni yuvası veya yöntem geçici değişkeni durumunda doğrudan bayt koduna kopyalanacak bir ofset olarak ya da paylaşılan değişken durumu için bir tür İlişkilendirme olarak çözdü, bu ilişki genellikle CompiledMethod değişmezlerine eklenir ve bu değişkenle ilgilenen tüm yöntemler arasında etkin bir şekilde paylaşılır (tüm yöntemler, etkin bir şekilde paylaşılan aynı Assocation nesnesine işaret eder).
Derleyici kısmı çok daha fazla lehçeye özgüdür, Squeak'ta paylaşılan değişkenlerin bağlanmasını çözmek için kullanılan bu yöntemdir:
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
Bu size Smalltalk'ın en ilginç bölümlerinden birinin IDE'nin içinden uygulamaya girebilmeniz olduğunu hatırlatmak için Smalltalk aslında Smalltalk'ta yazılmıştır!