Di mana variabel kelas didefinisikan di Smalltalk?
Saya bertanya-tanya, jika saya mendefinisikan variabel kelas baru, misalnya untuk kelas MyClass
, apakah definisinya akan masuk MyClass
atau masuk MyClass class
? Apakah MyClass class
tahu tentang variabel kelas baru?
Jawaban
Ya, variabel kelas dibagikan dengan kelas dan metaclass. Mereka juga dibagikan dengan semua subclass (dan metaclass-nya). Variabel kelas biasanya menggunakan huruf kapital, untuk menyampaikan gagasan yang lebih baik tentang berbagi dalam ruang lingkup yang lebih luas daripada kelas. Anda mendefinisikan variabel kelas di kelas (bukan metaclass).
Variabel kelas tidak boleh disamakan dengan variabel instan kelas, yang merupakan variabel instan yang didefinisikan pada tingkat metaclass, yaitu variabel instan dari objek kelas. Gagasan ini agak kabur meskipun sederhana (atau karena itu): variabel instance selalu ditentukan di kelas untuk menentukan bentuk (slot) dari instance-nya . Jadi, jika kita menerapkan definisi ini ke metaclass, yang merupakan kelas dari kelas tersebut, variabel instance yang didefinisikan di sini mendefinisikan bentuk instance-nya, yang (biasanya) hanya ada satu kelas.
Kembali ke variabel kelas, Anda mendefinisikannya di kelas (sisi inst) dan menginisialisasinya dalam metaclass (yaitu, sisi kelas). Ingatlah bahwa ini adalah global (parsial) dalam arti yang akan dibagikan di antara instance, subinstance, subclass dan metaclass sehingga mereka harus ditangani dengan hati-hati seperti biasa kita memperlakukan global.
Satu klarifikasi lagi
Ketika kami mengatakan bahwa variabel instan dibagi di antara instance dan subinstance, yang kami maksud adalah nama mereka (dan posisi dalam memori slot objek); yang kami maksud bukan nilai mereka (isi slot tersebut). Jadi, dua instance kelas C
akan berbagi nama, katakanlah color
, jika kelas tersebut mendefinisikan ivar color
, tetapi nilainya di masing-masing instance akan independen. Dengan kata lain, yang dibagikan adalah namanya, bukan nilainya.
Dengan variabel kelas, yang dibagi adalah nama dan nilainya. Ini sebenarnya adalah Association
objek, misalnya Theme -> aTheme
, apa yang dibagikan. Akibatnya, setiap modifikasi nilai variabel kelas mempengaruhi semua referensinya. Hal ini tidak terjadi pada variabel instance kelas karena mereka tidak lain adalah variabel instance, kecuali bahwa variabel tersebut membentuk kelas dan subkelasnya, bukan instance dan subinstance biasa.
Untuk informasi lebih lanjut tentang variabel Smalltalk, lihat https://stackoverflow.com/a/42460583/4081336
Sebagai pelengkap jawaban Leandro, berikut adalah metode spesifik implementasi Squeak utama yang menjelaskan pembagian variabel kelas antara sisi instance (kelas) dan sisi kelas (metaclass):
Metaclass>>classPool
"Answer the dictionary of class variables."
^thisClass classPool
di mana thisClass
contoh unik dari Metaclass, yaitu kelas itu sendiri ...
Namun, ada kemungkinan besar untuk menemukan implementasi serupa di sebagian besar dialek Smalltalk.
Kompilator pertama-tama akan mencoba menyelesaikan variabel sebagai metode / blok sementara (termasuk parameter methd / blok), kemudian variabel instan, kemudian variabel bersama.
Metode classPool dikirim oleh kompilator pada fase terakhir ini.
Leandro memang menjelaskan, kompilator menyelesaikan pengikatan seperti offset yang akan langsung ditranskripsikan dalam bytecode dalam kasus slot variabel instans atau variabel sementara metode, atau sebagai semacam Asosiasi untuk kasus variabel bersama, asosiasi ini umumnya ditambahkan ke literal CompiledMethod dan secara efektif dibagikan di antara semua metode yang menangani variabel ini (semua metode menunjuk ke objek Assocation yang sama yang secara efektif dibagikan).
Bagian kompiler jauh lebih spesifik dialek, di Squeak, metode inilah yang digunakan untuk menyelesaikan pengikatan variabel bersama:
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
Ini untuk mengingatkan Anda bahwa salah satu bagian paling menarik dari Smalltalk adalah Anda dapat menggali implementasi dari dalam IDE, Smalltalk pada dasarnya ditulis dalam Smalltalk!