Tenun kode byte vs makro Lisp

11

Saya telah membaca tentang perpustakaan yang ditulis orang untuk bahasa seperti Java dan C # yang menggunakan tenun kode byte untuk melakukan hal-hal seperti panggilan fungsi intersep, memasukkan kode logging, dll. Saya juga membaca di Lisp / Clojure macro di sebuah mencoba untuk lebih memahami bagaimana memanfaatkannya. Semakin banyak saya membaca tentang makro, semakin banyak sepertinya mereka menyediakan fungsionalitas yang sama dengan perpustakaan byte code tenun. Secara fungsional, maksud saya kemampuan untuk memanipulasi kode pada waktu kompilasi.

Contoh perpustakaan yang telah saya lihat adalah AspectJ, PostSharp, dan Cecil.

Adakah yang bisa dilakukan dengan yang satu dan bukan yang lain? Apakah mereka benar-benar memecahkan masalah yang sama atau apakah saya membandingkan apel dan jeruk?

mortalapeman
sumber
2
tenun kode byte adalah penyelesaian ketika Anda membutuhkan bahasa yang dinamis tetapi terjebak dengan bahasa yang diketik secara statis
kevin cline
2
@ kevincline apakah Anda serius mencoba memulai pertarungan lama ini?
Jonathan Henson

Jawaban:

10

Tenun kode byte dan makro adalah dua hal yang berbeda.

Tenun kode byte adalah cara untuk mencegat panggilan fungsi, sehingga Anda dapat menyuntikkan semacam fungsionalitas (umumnya masalah lintas sektoral seperti pencatatan) ke dalam panggilan fungsi, baik sebelum atau setelah fungsi dijalankan. Tenun kode byte dilakukan pada level kode byte, yang berarti terjadi setelah kompilasi. Fungsi itu sendiri tidak terpengaruh. Ini adalah salah satu teknik yang digunakan Pemrograman Berorientasi Aspek .

Makro adalah cara untuk memperpanjang sintaks suatu bahasa. Dalam bentuknya yang paling sederhana, makro hanyalah cara untuk merekam penekanan tombol, dan kemudian memutarnya menggunakan hot key. Makro bahasa bekerja dengan cara yang sama; kata kunci atau sintaks konstruksi pengganti untuk beberapa jenis ekspansi makro. Ini terlalu disederhanakan, tentu saja; contoh makro khusus untuk Lisp yang lebih baik dapat ditemukan di sini .

Robert Harvey
sumber
+1 untuk menyebutkan bahwa ini adalah cara utama menerapkan AOP.
Jonathan Henson
Dan transaksi ... janganlah kita melupakan transaksi.
Jonathan Henson
3
Makro LISP tidak seperti 'cara merekam penekanan tombol'.
kevin cline
1
Nah beberapa konsep dasar yang hilang untuk jawaban IMO, itu bisa: AST, refleksi, Metacircularity.
AndreasScheinert
2
@AndreasScheinert: OP tidak bertanya tentang hal-hal itu. Ini bukan disertasi; itu hanya jawaban untuk pertanyaan OP.
Robert Harvey
5

Meskipun mereka dapat digunakan untuk tujuan yang sama, makro LISP sangat berbeda dari plugin tenun kode byte Java. Makro LISP memperluas sintaks LISP di tingkat kode sumber LISP. Karena makro LISP ditulis pada tingkat yang sama dengan kode LISP lainnya, mereka adalah fitur bahasa yang umum digunakan.

Plugin tenun kode byte Java beroperasi pada level JVM. Sementara banyak programmer Java dapat menggunakan plugin tenun byte-code yang ditulis oleh orang lain, sangat sedikit programmer Java yang menulis plugin tenun byte-code mereka sendiri.

Beberapa pekerjaan yang dilakukan oleh plugin kompiler Java sangat mudah dilakukan dalam bahasa dinamis. Intersepsi panggilan fungsi sangat sederhana.

kevin cline
sumber
Saya mengerti perbedaan teknis antara keduanya. Saya berusaha melihat pertanyaan dari sudut pandang tingkat tinggi. Bisakah kedua alat memanipulasi kode untuk mencapai tujuan yang sama? Apakah ada masalah yang tidak dapat diselesaikan makro yang dapat dimanipulasi oleh bytecode (dengan cara yang waras dan hemat biaya)? Itulah yang saya inginkan.
mortalapeman
@mortalapeman: manipulasi yang dimungkinkan di Jawa dan C # melalui modifikasi byte-code semuanya dapat dilakukan secara langsung dalam bahasa seperti Lisp, Ruby, Python, Lua, Javascript ... Agaknya mungkin untuk melakukan segala sesuatu yang dapat dilakukan oleh makro LISP melalui byte. manipulasi-kode, tetapi dalam praktiknya itu tidak terjadi.
kevin cline
4

Macro Lisp beroperasi di tingkat kode sumber. Jika Anda membungkus makro di sekitar sepotong kode, maka Anda dapat melakukan banyak hal. Termasuk penguraian kode sumber, memasukkan kode, menulis ulang kode, dll.

Jika Anda ingin memodifikasi panggilan fungsi, Lisp biasanya menggunakan dua mekanisme:

  • simbol pengikat yang terlambat. Anda dapat memodifikasi fungsi yang terikat pada simbol. Setiap pemanggilan fungsi yang melewati simbol, lalu menggunakan fungsi baru.

  • Implementasi Lisp terkadang menyediakan fitur yang disebut 'saran'. Ini memungkinkan untuk mengeksekusi kode sebelum, setelah atau sekitar panggilan. Misalnya di LispWorks: Saran .

Dengan demikian Anda dapat mencegat panggilan tanpa manipulasi kode tingkat rendah.

Rainer Joswig
sumber