Apa sebenarnya metaprogramming itu?

128

Saya sedang membaca artikel di TheServerSide tentang pemrograman ployglot di platform Java . Beberapa komentar dalam artikel tersebut merujuk pada metaprogramming sebagai kemampuan untuk menghasilkan kode (mungkin dengan cepat).

Apakah metaprogramming adalah kemampuan untuk menghasilkan kode dengan cepat atau apakah itu kemampuan untuk memasukkan metode dan atribut ke dalam objek yang ada saat runtime (seperti yang diizinkan oleh beberapa bahasa dinamis seperti Python, Ruby, dan Groovy).

Parag
sumber
7
Anda mungkin tertarik dengan jawaban ini stackoverflow.com/questions/2565572/…
ewernli
@ewernli: Jawaban itu sebenarnya lebih baik daripada jawaban mana pun di sini!
JD

Jawaban:

100

Metaprogramming mengacu pada berbagai cara program memiliki pengetahuan tentang dirinya sendiri atau dapat memanipulasi dirinya sendiri.

Dalam bahasa seperti C #, refleksi adalah bentuk metaprogramming karena program dapat memeriksa informasi tentang dirinya sendiri. Misalnya mengembalikan daftar semua properti suatu objek.

Dalam bahasa seperti ActionScript, Anda dapat mengevaluasi fungsi saat runtime untuk membuat program baru seperti eval ("x" + i). DoSomething () akan mempengaruhi objek yang disebut x1 ketika i bernilai 1 dan x2 jika i bernilai 2.

Akhirnya, bentuk umum lain dari metaprogramming adalah ketika program dapat mengubah dirinya sendiri dengan cara yang tidak sepele. LISP terkenal akan hal ini dan merupakan sesuatu yang diperjuangkan oleh Paul Graham sekitar satu dekade lalu. Saya harus mencari beberapa esai spesifiknya. Tetapi idenya adalah bahwa program akan mengubah bagian lain dari program berdasarkan statusnya. Ini memungkinkan tingkat fleksibilitas untuk membuat keputusan pada waktu proses yang sangat sulit dalam sebagian besar bahasa populer saat ini.

Perlu juga dicatat bahwa di masa lalu yang baik pemrograman dalam perakitan langsung, program yang mengubah dirinya sendiri pada waktu proses diperlukan dan sangat umum.

Dari esai Paul Graham "What Made Lisp Different" :

Banyak bahasa memiliki sesuatu yang disebut makro. Tapi makro Lisp unik. Dan percaya atau tidak, apa yang mereka lakukan terkait dengan tanda kurung. Para desainer Lisp tidak memasukkan semua tanda kurung itu dalam bahasa hanya untuk membuat perbedaan. Bagi programmer Blub, kode Lisp terlihat aneh. Tapi tanda kurung itu ada karena suatu alasan. Mereka adalah bukti lahiriah dari perbedaan mendasar antara Lisp dan bahasa lain.

Kode Lisp dibuat dari objek data Lisp. Dan bukan dalam arti sepele bahwa file sumber berisi karakter, dan string adalah salah satu tipe data yang didukung oleh bahasa. Kode Lisp, setelah dibaca oleh parser, dibuat dari struktur data yang dapat Anda lintasi.

Jika Anda memahami cara kerja kompiler, apa yang sebenarnya terjadi bukanlah Lisp memiliki sintaks yang aneh karena Lisp tidak memiliki sintaks. Anda menulis program di pohon parse yang dihasilkan di dalam kompiler ketika bahasa lain diurai. Tetapi pohon parse ini sepenuhnya dapat diakses oleh program Anda. Anda dapat menulis program yang memanipulasinya. Di Lisp, program ini disebut makro. Mereka adalah program yang menulis program.

Program yang menulis program? Kapan Anda ingin melakukan itu? Tidak terlalu sering, jika Anda berpikir di Cobol. Sepanjang waktu, jika Anda berpikir di Lisp. Akan lebih mudah di sini jika saya dapat memberikan contoh makro yang kuat, dan berkata di sana! bagaimana tentang itu? Tetapi jika saya melakukannya, itu akan terlihat seperti omong kosong bagi seseorang yang tidak mengenal Lisp; tidak ada ruang di sini untuk menjelaskan semua yang perlu Anda ketahui untuk memahami apa artinya. Di Ansi Common Lisp saya mencoba untuk memindahkan semuanya secepat yang saya bisa, dan meskipun demikian saya tidak membuka makro sampai halaman 160.

Tapi saya rasa saya bisa memberikan argumen yang mungkin meyakinkan. Kode sumber editor Viaweb mungkin sekitar 20-25% makro. Makro lebih sulit untuk ditulis daripada fungsi Lisp biasa, dan ini dianggap gaya yang buruk untuk digunakan saat tidak diperlukan. Jadi setiap makro dalam kode itu ada karena harus ada. Artinya, setidaknya 20-25% kode dalam program ini melakukan hal-hal yang tidak dapat Anda lakukan dengan mudah dalam bahasa lain. Betapapun skeptisnya programmer Blub tentang klaim saya atas kekuatan misterius Lisp, ini seharusnya membuatnya penasaran. Kami tidak menulis kode ini untuk kesenangan kami sendiri. Kami adalah perusahaan rintisan kecil, memprogram sekeras yang kami bisa untuk menempatkan hambatan teknis antara kami dan pesaing kami.

Orang yang mencurigakan mungkin mulai bertanya-tanya apakah ada korelasi di sini. Sebagian besar kode kami melakukan hal-hal yang sangat sulit dilakukan dalam bahasa lain. Perangkat lunak yang dihasilkan melakukan hal-hal yang tidak dapat dilakukan perangkat lunak pesaing kami. Mungkin ada semacam hubungan. Saya mendorong Anda untuk mengikuti utas itu. Mungkin ada lebih banyak hal dari orang tua yang tertatih-tatih di tongkatnya itu daripada yang terlihat.

DavGarcia
sumber
6
Jangan lupa tentang metaprogramming template di C ++. Kemampuan untuk mengeksekusi ekspresi dan membuat keputusan pada waktu kompilasi, dan membuat hasilnya dikompilasi secara statis ke dalam eksekusi akhir.
Remy Lebeau
1
Saya terkejut in order to put technical barriers between us and our competitorsdan ini benar.
Evan Hu
4
Program yang memanipulasi dirinya sendiri adalah bagian dari semua metaprogram. Metaprogramming secara umum hanya berarti program yang memanipulasi program.
JD
55

Pertanyaan bagus. Saya sangat menyesal melihat tidak ada jawaban yang saat ini benar-benar menjawab pertanyaan Anda dengan benar. Mungkin saya bisa membantu ...

Definisi metaprogramming sebenarnya cukup sederhana: itu berarti program yang memanipulasi program.

Jawaban Anda yang diterima mengatakan program yang memanipulasi dirinya sendiri. Itu memang metaprogram tetapi mereka adalah bagian dari semua metaprogram.

Semua:

  • Parser
  • Bahasa khusus domain (DSL)
  • Bahasa khusus domain tersemat (EDSL)
  • Penyusun
  • Penerjemah
  • Penulis ulang istilah
  • Pembuktian teorema

adalah metaprogram. Jadi kompiler GCC adalah metaprogram, interpreter CPython adalah metaprogram, sistem aljabar komputer Mathematica adalah metaprogram, prover teorema Coq adalah metaprogram dan seterusnya.

Jawaban lain telah menegaskan bahwa metaprogram adalah program yang menghasilkan program lain. Itu memang metaprogram tetapi, sekali lagi, mereka adalah bagian dari semua metaprogram. The Tercepat Fourier Transform di Barat (FFTW) perpustakaan adalah contoh dari metaprogram sebuah tersebut. Kode sumber sebagian besar ditulis dalam OCaml dan menghasilkan bit kode C (disebut codelet) yang digabungkan untuk membuat rutinitas Fast Fourier Transform berkinerja tinggi yang dioptimalkan untuk mesin tertentu. Library tersebut sebenarnya digunakan untuk menyediakan rutinitas FFT di Matlab. Orang-orang telah menulis program untuk menghasilkan metode numerik selama beberapa dekade, sejak masa awal FORTRAN .

Bahasa pemrograman pertama yang mengintegrasikan dukungan untuk metaprogramming adalah bahasa LISt Processor (LISP) pada akhir 1950-an. LISP 1.5 menyertakan sejumlah fitur yang membuat metaprogramming lebih mudah. Pertama, tipe data inti LISP adalah daftar bersarang, yaitu seperti pohon (a (b c) d), yang berarti setiap kode LISP dapat diekspresikan secara native sebagai struktur data. Ini dikenal sebagai homoikonisitas. Kedua, kode LISP dapat diubah menjadi data dengan mudah menggunakan QUOTE. Misalnya (+ 1 2 3)menambahkan 1 + 2 + 3 dan (QUOTE (+ 1 2 3))membuat ekspresi yang menambahkan 1 + 2 + 3 saat dievaluasi. Ketiga, LISP menyediakan meta-circular evaluator yang memungkinkan Anda menggunakan interpreter host atau compiler untuk mengevaluasi kode LISP pada saat run-time, termasuk kode LISP yang dihasilkan run-time. Keturunan LISP termasuk Skema dan Clojure. Dalam semua bahasa ini, metaprogramming paling sering terlihat dalam bentuk program yang memodifikasi dirinya sendiri, biasanya menggunakan makro.

Pada 1970-an, Robin Milner mengembangkan MetaLanguage (ML) yang berkembang menjadi keluarga bahasa pemrograman ML yang mencakup Standard ML dan OCaml dan sangat memengaruhi Haskell dan F # . Bahasa-bahasa ini memudahkan untuk mengekspresikan bahasa lain. Dalam bahasa-bahasa ini metaprogram paling sering terlihat dalam bentuk lexers, parser, interpreter dan compiler.

Pada tahun 1994, Erwin Unruh menemukan bahwa sistem template C ++ Turing sudah lengkap dan dapat digunakan untuk mengeksekusi program sewenang-wenang pada waktu kompilasi . C ++ template metaprogramming membawa metaprogramming ke massa yang tidak dicuci yang (ab) menggunakannya untuk banyak hal berbeda termasuk menghasilkan metode numerik di pustaka Blitz ++ .

JD
sumber
33

Nah, metaprogramming hanyalah pemrograman, tapi pada dasarnya "menulis kode yang menulis kode" .

Kemampuan yang Anda sebutkan, ketika suatu program dapat mengamati dan memodifikasi struktur dan perilakunya sendiri disebut refleksi dan itu adalah jenis metaprogramming.

Bahasa yang diketik secara dinamis, memiliki fitur refleksi waktu proses yang kuat, dimungkinkan oleh sifat bahasa yang ditafsirkan ...

Bahasa tipe statis juga memiliki teknik metaprogramming yang kuat, misalnya metaprogramming template C ++ ...

CMS
sumber
14

Ini hanya pendapat pribadi saya, yang mungkin merupakan definisi metaprogramming yang paling liberal.

Saya pikir itu termasuk:

  1. Kompilasi pembuatan kode atau pembuatan kode runtime (atau keduanya)
  2. Pemrograman Berorientasi Aspek atau Pemrograman Berorientasi Aspek
  3. Berpikir KERING

Saya pikir Anda bisa sampai di sana dengan menggunakan salah satu dari ini dan dalam kombinasi:

  1. Refleksi
  2. DSL (Bahasa Tertentu Domain)
  3. Atribut (.NET) atau Anotasi (Java)
  4. Generik (.NET / Java)
  5. Template (C ++)
  6. method_missing (Ruby)
  7. penutupan / fungsi / delegasi kelas satu
  8. AOP - Pemrograman Berorientasi Aspek
BuddyJoe
sumber
jawaban yang sangat ringkas dan bijaksana. memberi saya menu bagus untuk diselidiki. Terima kasih!
swyx
6

Metaprogramming adalah menulis program yang mengeluarkan program lain. Ini adalah sesuatu yang sangat bagus dalam bahasa seperti Lisp. Jauh lebih mudah dilakukan dalam bahasa yang mendukung makro nyata (bukan makro C ++, melainkan yang dapat memanipulasi kode yang mereka keluarkan) seperti Ruby, Lisp, Skema, dll. Daripada dalam bahasa seperti Java.

Salah satu implementasinya adalah membuat "domain specific language" yang merupakan cara menyempurnakan bahasa pemrograman untuk menyelesaikan tugas tertentu. Ini bisa menjadi sangat kuat jika dilakukan dengan benar. Ruby on Rails adalah contoh yang bagus untuk pemrograman semacam ini.

Jika Anda tertarik untuk mengeksplorasi metode ini, lihat Struktur dan Interpretasi Program Komputer yang merupakan salah satu buku penting yang membahas subjek.

Steve Rowe
sumber
5

Metaprogramming adalah penulisan program komputer yang menulis atau memanipulasi program lain (atau dirinya sendiri) sebagai datanya, atau yang melakukan sebagian pekerjaan pada saat runtime yang seharusnya dilakukan pada waktu kompilasi. Dalam banyak kasus, ini memungkinkan pemrogram untuk menyelesaikan lebih banyak dalam jumlah waktu yang sama seperti yang mereka perlukan untuk menulis semua kode secara manual, atau memberikan program fleksibilitas yang lebih besar untuk menangani situasi baru secara efisien tanpa kompilasi ulang. ( Sumber .)

Pada dasarnya, ini menulis kode yang menghasilkan lebih banyak kode, yang dijalankan untuk mencapai beberapa tujuan. Ini biasanya dilakukan baik dalam bahasa yang sama (menggunakan javascript untuk membuat string javascript, kemudian evalitu) atau untuk memancarkan bahasa lain (menggunakan .NET untuk membuat file batch windows).

EndangeredMassa
sumber
4

wikipedia memiliki artikel bagus tentang topik tersebut. Seseorang tidak perlu melakukan modifikasi runtime untuk sesuatu agar memenuhi syarat sebagai metaprogramming. Misalnya, banyak orang menggunakan template C ++ untuk melakukan metaprogramming pada waktu kompilasi.

Tuan Fooz
sumber