Bagaimana kompiler mengetahui tentang kelas lain dan propertinya?

14

Saya sedang menulis bahasa pemrograman pertama saya yang berorientasi objek dan sejauh ini bagus dengan membuat satu 'kelas'. Tapi, katakanlah saya ingin kuliah, katakan ClassAdan ClassB. Asalkan keduanya tidak ada hubungannya satu sama lain maka semuanya baik-baik saja. Namun, katakanlah ClassAmenciptakan ClassB- ini menimbulkan 2 pertanyaan terkait:

-Bagaimana kompiler tahu kapan kompilasi ClassAitu ClassBada, dan, jika ada, bagaimana ia tahu sifat-sifatnya?

Pikiranku sejauh ini adalah: daripada mengkompilasi setiap kelas pada satu waktu (yaitu memindai, mengurai dan menghasilkan kode) setiap "file (tidak benar-benar file, per se, tetapi" kelas ") yang saya perlukan untuk memindai + mengurai setiap pertama , lalu buat kode untuk semua?

OnResolve
sumber

Jawaban:

13

Bahasa yang berbeda (dan karenanya penyusun) pendekatan ini berbeda.

Dalam keluarga C, modul yang berbeda memiliki file header yang sesuai yang digunakan saat membangun objek. File header memberikan informasi tentang ukuran objek dan fungsi atau metode apa yang ada yang dapat dipanggil. Ini memungkinkan informasi yang diperlukan untuk alokasi memori dan "apakah ada metode / fungsi / prosedur itu?" yang digunakan saat melakukan kompilasi satu unit yang tidak perlu memiliki akses ke sumber itu sendiri.

Di Jawa, kompilator mengetahui hal-hal di classpath-nya dan memeriksa objek-objek itu untuk dihubungkan dengannya (memverifikasi bahwa ada metode, memiliki jumlah argumen yang tepat, dll ...). Java juga dapat menautkan secara dinamis saat runtime memuat di kelas lain yang tidak diketahuinya saat dikompilasi. Lihat Class.forName untuk satu contoh pemuatan dinamis.

Kedua opsi ini cukup valid dan memiliki kelebihan dan kekurangan masing-masing. Menyediakan beberapa file header yang dianggap rumit dan melanggar KERING . Di sisi lain, jika Anda tidak memiliki file header, pustaka perlu diperiksa oleh kompiler dan tautan - a .so atau .dll kemungkinan tidak akan memiliki cukup informasi di dalamnya untuk membuat instance objek dengan benar atau memvalidasi pemanggilan metode ( dan akan bergantung pada mesin).

Komunitas
sumber
0

Secara praktis, dengan Java, tampilan IDE pada keseluruhan program sekaligus; ketika ClassB direferensikan, kompiler IDE akan melihatnya. Semuanya, termasuk perpustakaan, adalah satu keseluruhan yang lengkap. Setelah program siap, Anda dapat mengubah jalur kelas, menukar masuk dan keluar file .class individu, dan beralih versi perpustakaan. Anda juga dapat mengkompilasi file individu .java tanpa menggunakan IDE (atau entah bagaimana menghindari cek itu). Hasilnya tidak perlu konsisten sama sekali, dan jika tidak, Anda akan mendapatkan pengecualian run-time. (Salah satu dari banyak hal yang coba dilakukan oleh IDE untuk Anda adalah mengubah kesalahan waktu-pakai menjadi waktu kompilasi, atau lebih tepatnya, waktu edit, kesalahan.)

C # kira-kira sama, dan saya tidak berpikir C dan C ++ benar-benar berbeda, dalam apa yang Java dan C # IDE lakukan hanyalah membuat header gaya C / C ++ untuk Anda di belakang layar.

RalphChapin
sumber
Kompiler Java mengkompilasi hal-hal yang tergantung juga, jika perlu. Anda hanya mendapatkan pengecualian runtime dari hal semacam ini jika Anda benar-benar berusaha sangat keras untuk memaksakan sesuatu (misalnya, mengubah dan mengkompilasi ulang API setelah mengkompilasi konsumen API itu).
Donal Fellows
@DonalFellows: Masalah saya ada di perpustakaan yang hilang ("Tapi saya meletakkan yang itu di semua mesin saya!") Dan mengkompilasi ulang program yang sedang berjalan (file hotclass bertukar panas yang tidak sengaja). Saya dapat melihat pembaruan paket yang tidak lagi cocok dengan program utama, meskipun saya belum melakukannya. Saya melakukan melakukan banyak yang dengan C dan ini .dll (dan telah melakukannya untuk saya) tahun yang lalu. Saya percaya dan berharap ada banyak perlindungan di tempat sekarang yang tidak ada di sana.
RalphChapin
Saya benar-benar tidak mengerti apa yang harus dilakukan oleh IDE dengan bagaimana seorang kompiler / penghubung mengetahui bagaimana memecahkan masalah kompilasi / penghubung. Perbaiki saya jika saya salah, tetapi sebuah IDE benar-benar ortogonal untuk seluruh masalah (kecuali bahwa itu memudahkan tugas pada programmer). Mengapa? Karena secara teori, IDE menggunakan kompiler di latar belakang.
Thomas Eding
@ Thomas: Anda benar sekali. Ketika saya menjawab pertanyaan ini, saya sepertinya kesulitan memisahkan IDE dari compiler / linker. Alasan saya: Java tidak "menautkan" sampai berjalan dan jadi tidak bisa tahu ref kelas atau pemanggilan metode salah sampai saat itu; IDE tidak benar-benar "memudahkan" tugas saya, itu memungkinkan. Saya menggunakan (dalam FORTRAN dan C, jauh sebelumnya) untuk mendapatkan kesalahan ketika saya kompilasi, ketika saya ditautkan, dan kemudian ketika saya berlari. Sekarang saya mendapatkan hampir semua kesalahan itu dengan benar ketika saya mengetiknya, yang membuat IDE kompiler, linker, dan executer, dalam arti tertentu. Hari ini, semua kesalahan non-run-time berasal dari IDE.
RalphChapin
0

Bahasa yang lebih tua terkadang lebih ketat; pertimbangkan apa yang mungkin di Jawa:

public interface Ifc {
    public static final Ifc MY_CONSTANT = new Implem();
}

public class Implem implements Ifc {
}

Saya telah melihat anti-pola di atas, dan itu benar - benar jelek (saya akan melarangnya). Kedua unit kompilasi saling menggunakan. Tetapi Ifc dapat dikompilasi ke kode tanpa Implem yang dikompilasi. Kode yang dikompilasi, .class, sebanding dengan C.obj, berisi "informasi tautan:" impor Implem, memanggil konstruktor tanpa parameter Implem(). Kelas Implem kemudian dapat dikompilasi tanpa masalah. Sebagian ClassLoader - melakukan inisialisasi / membangun data kelas JVM, dan sebagian Java Virtual Machine itu sendiri, bermain sedikit sebagai penghubung , mengintegrasikan semua.

Misalnya mengkompilasi dengan satu versi dari perpustakaan tertentu, dan menjalankan dengan versi lain dari perpustakaan itu akan mengenali kesalahan runtime.

Jadi jawabannya: Kompilasi memberikan unit kode objek yang dikompilasi, yang harus dilihat sebagai kode + data + API untuk dihubungkan bersama.

Kompiler kemudian harus juga melakukan pengepakan bersama, dan memverifikasi tautan API; fase kedua.

Ini mungkin menjengkelkan dan terlihat tidak bagus, tetapi bukti matematis dapat beroperasi dengan cara yang sama: dalam membuktikan seluruh kebenaran seseorang mungkin sudah mempertimbangkan bagian untuk tetap benar sampai verifikasi.

Joop Eggen
sumber