Saya tahu bahwa programmer Lisp dan Skema biasanya mengatakan bahwa eval
harus dihindari kecuali sangat diperlukan. Saya telah melihat rekomendasi yang sama untuk beberapa bahasa pemrograman, tetapi saya belum melihat daftar argumen yang jelas terhadap penggunaan eval
. Di mana saya dapat menemukan akun tentang potensi masalah menggunakan eval
?
Sebagai contoh, saya tahu masalah GOTO
dalam pemrograman prosedural (membuat program tidak dapat dibaca dan sulit dirawat, membuat masalah keamanan sulit ditemukan, dll), tetapi saya belum pernah melihat argumen yang menentangnya eval
.
Menariknya, argumen yang sama terhadap GOTO
harus valid terhadap kelanjutan, tetapi saya melihat bahwa Schemers, misalnya, tidak akan mengatakan bahwa kelanjutan adalah "jahat" - Anda harus berhati-hati saat menggunakannya. Mereka lebih cenderung berkerut pada penggunaan kode eval
daripada pada kode menggunakan kelanjutan (sejauh yang saya bisa melihat - saya bisa salah).
Jawaban:
Ada beberapa alasan mengapa seseorang tidak boleh menggunakannya
EVAL
.Alasan utama untuk pemula adalah: Anda tidak membutuhkannya.
Contoh (dengan asumsi Common Lisp):
EVALuasikan ekspresi dengan operator yang berbeda:
Itu lebih baik ditulis sebagai:
Ada banyak contoh di mana pemula belajar Lisp berpikir mereka butuhkan
EVAL
, tetapi mereka tidak membutuhkannya - karena ekspresi dievaluasi dan orang juga dapat mengevaluasi bagian fungsi. Sebagian besar waktu penggunaanEVAL
menunjukkan kurangnya pemahaman evaluator.Ini adalah masalah yang sama dengan makro. Seringkali pemula menulis makro, di mana mereka harus menulis fungsi - tidak memahami apa sebenarnya makro dan tidak memahami bahwa fungsi sudah melakukan pekerjaan.
Ini sering merupakan alat yang salah untuk pekerjaan yang harus digunakan
EVAL
dan sering menunjukkan bahwa pemula tidak memahami aturan evaluasi Lisp yang biasa.Jika Anda merasa perlu
EVAL
, periksa apakah ada yang sukaFUNCALL
,REDUCE
atauAPPLY
bisa digunakan.FUNCALL
- panggil fungsi dengan argumen:(funcall '+ 1 2 3)
REDUCE
- panggil fungsi pada daftar nilai dan gabungkan hasilnya:(reduce '+ '(1 2 3))
APPLY
- memanggil fungsi dengan daftar sebagai argumen:(apply '+ '(1 2 3))
.T: apakah saya benar-benar membutuhkan eval atau apakah kompiler / evaluator sudah seperti yang saya inginkan?
Alasan utama untuk menghindari
EVAL
pengguna yang sedikit lebih maju:Anda ingin memastikan bahwa kode Anda dikompilasi, karena kompiler dapat memeriksa kode untuk banyak masalah dan menghasilkan kode lebih cepat, kadang-kadang JAUH JAUH JAUH (itu faktor 1000 ;-)) kode lebih cepat
kode yang dibangun dan perlu dievaluasi tidak dapat dikompilasi sedini mungkin.
eval input pengguna sewenang-wenang membuka masalah keamanan
beberapa penggunaan evaluasi
EVAL
dapat terjadi pada waktu yang salah dan menimbulkan masalah pembangunanUntuk menjelaskan poin terakhir dengan contoh sederhana:
Jadi, saya mungkin ingin menulis makro yang didasarkan pada parameter pertama menggunakan salah satu
SIN
atauCOS
.(foo 3 4)
lakukan(sin 4)
dan(foo 1 4)
lakukan(cos 4)
.Sekarang kita mungkin memiliki:
Ini tidak memberikan hasil yang diinginkan.
Seseorang kemudian mungkin ingin memperbaiki makro
FOO
dengan MENGEVALUASI variabel:Tapi ini masih tidak berhasil:
Nilai variabel tidak diketahui pada waktu kompilasi.
Alasan umum yang penting untuk dihindari
EVAL
: sering digunakan untuk peretasan yang buruk.sumber
eval
hanya karena mereka tidak tahu ada fitur bahasa atau perpustakaan tertentu untuk melakukan apa yang ingin mereka lakukan. Contoh serupa dari JS: Saya ingin mendapatkan properti dari objek menggunakan nama dinamis, jadi saya menulis:eval("obj.+" + propName)
ketika saya bisa menulisobj[propName]
."obj.+"
? Terakhir saya periksa,+
tidak valid ketika menggunakan referensi-titik di JS.eval
(dalam bahasa apa pun) tidak jahat dengan cara yang sama seperti gergaji mesin yang tidak jahat. Itu adalah alat. Kebetulan itu adalah alat yang ampuh yang, ketika disalahgunakan, dapat memutuskan anggota tubuh dan mengeluarkan isi perut (berbicara secara metaforis), tetapi hal yang sama dapat dikatakan untuk banyak alat di kotak alat programmer termasuk:goto
dan teman-temanJika Anda harus menggunakan alat yang kuat dan berpotensi berbahaya ini, tanyakan pada diri sendiri tiga kali "mengapa?" dalam sebuah rantai. Sebagai contoh:
Jika Anda sampai ke ujung rantai itu dan alat itu masih terlihat seperti itu adalah hal yang benar untuk dilakukan, maka lakukanlah. Dokumentasikan Neraka keluar dari itu. Uji Neraka keluar dari itu. Periksa kebenaran dan keamanan berulang-ulang. Tapi lakukan itu.
sumber
Eval baik-baik saja, selama Anda tahu PERSIS apa yang masuk ke dalamnya. Setiap input pengguna yang masuk ke dalamnya HARUS diperiksa dan divalidasi dan semuanya. Jika Anda tidak tahu bagaimana menjadi 100% yakin, maka jangan lakukan itu.
Pada dasarnya, pengguna dapat mengetikkan kode apa saja untuk bahasa yang bersangkutan, dan itu akan dijalankan. Anda bisa bayangkan sendiri berapa banyak kerusakan yang bisa dia lakukan.
sumber
"Kapan saya harus menggunakan
eval
?" mungkin pertanyaan yang lebih baik.Jawaban singkatnya adalah "ketika program Anda dimaksudkan untuk menulis program lain saat runtime, dan kemudian jalankan". Pemrograman genetika adalah contoh dari situasi di mana kemungkinan masuk akal untuk digunakan
eval
.sumber
IMO, pertanyaan ini tidak spesifik untuk LISP . Berikut ini adalah jawaban untuk pertanyaan yang sama untuk PHP, dan itu berlaku untuk LISP, Ruby, dan bahasa lain yang memiliki eval:
Diambil dari sini .
Saya pikir tipuan adalah hal yang luar biasa. Obsesi dengan kode golf dan kode ringkas selalu menghasilkan kode "pintar" (yang eval adalah alat yang hebat). Tetapi Anda harus menulis kode Anda agar mudah dibaca, IMO, bukan untuk menunjukkan bahwa Anda cerdas dan tidak menghemat kertas (toh Anda tidak akan mencetaknya).
Kemudian di LISP ada beberapa masalah terkait dengan konteks di mana eval dijalankan, sehingga kode yang tidak dipercaya bisa mendapatkan akses ke lebih banyak hal; masalah ini sepertinya sudah biasa.
sumber
Ada banyak jawaban bagus, tapi inilah yang lain dari Matthew Flatt, salah satu pelaksana Racket:
http://blog.racket-lang.org/2011/10/on-eval-in-dynamic-languages-generally.html
Dia membuat banyak poin yang telah dibahas tetapi beberapa orang mungkin menganggap pendapatnya menarik.
Rangkuman: Konteks di mana ia digunakan mempengaruhi hasil eval tetapi sering tidak dipertimbangkan oleh programmer, yang mengarah ke hasil yang tidak terduga.
sumber
Jawaban kanonik adalah menjauh. Yang saya temukan aneh, karena ini primitif, dan dari tujuh primitif (yang lain adalah kontra, mobil, cdr, jika, eq dan kutipan), semakin jauh menggunakan paling sedikit penggunaan dan cinta.
Dari On Lisp : "Biasanya, memanggil eval secara eksplisit seperti membeli sesuatu di toko suvenir bandara. Setelah menunggu sampai saat terakhir, Anda harus membayar harga tinggi untuk pilihan terbatas barang-barang kelas dua."
Jadi kapan saya menggunakan eval? Satu penggunaan normal adalah memiliki REPL dalam REPL Anda dengan mengevaluasi
(loop (print (eval (read))))
. Semua orang baik-baik saja dengan penggunaan itu.Tetapi Anda juga dapat mendefinisikan fungsi dalam hal makro yang akan dievaluasi setelah kompilasi dengan menggabungkan eval dengan backquote. Kamu pergi
dan itu akan membunuh konteks untuk Anda.
Swank (untuk slac emacs) penuh dengan kasus ini. Mereka terlihat seperti ini:
Saya tidak berpikir itu adalah hack kotor. Saya menggunakannya sepanjang waktu untuk mengintegrasikan kembali fungsi makro.
sumber
Beberapa poin lain pada Lisp eval:
sumber
Seperti "aturan" GOTO: Jika Anda tidak tahu apa yang Anda lakukan, Anda dapat membuat kekacauan.
Selain dari hanya membangun sesuatu dari data yang diketahui dan aman, ada masalah bahwa beberapa bahasa / implementasi tidak cukup mengoptimalkan kode. Anda bisa berakhir dengan kode yang ditafsirkan di dalamnya
eval
.sumber
Eval tidak aman. Misalnya Anda memiliki kode berikut:
Sekarang pengguna datang ke situs Anda dan masuk ke url http://example.com/file.php?user= ); $ is_admin = true; echo (
Maka kode yang dihasilkan adalah:
sumber
eval
bahasa apa pun yang memilikinya.Eval tidak jahat. Eval tidak rumit. Ini adalah fungsi yang menyusun daftar yang Anda lewati. Di sebagian besar bahasa lain, kompilasi kode arbitrer akan berarti mempelajari AST bahasa dan menggali internal kompiler untuk mengetahui API kompiler. Dalam cadel, Anda hanya memanggil eval.
Kapan sebaiknya Anda menggunakannya? Setiap kali Anda perlu mengkompilasi sesuatu, biasanya sebuah program yang menerima, membuat atau memodifikasi kode arbitrer saat runtime .
Kapan sebaiknya Anda tidak menggunakannya? Semua kasus lainnya.
Mengapa Anda tidak menggunakannya saat Anda tidak perlu? Karena Anda akan melakukan sesuatu dengan cara rumit yang tidak perlu yang dapat menyebabkan masalah keterbacaan, kinerja, dan debugging.
Ya, tetapi jika saya seorang pemula bagaimana saya tahu jika saya harus menggunakannya? Selalu mencoba menerapkan apa yang Anda butuhkan dengan fungsi. Jika itu tidak berhasil, tambahkan makro. Jika itu masih tidak berhasil, maka eval!
Ikuti aturan ini dan Anda tidak akan pernah melakukan kejahatan dengan eval :)
sumber
Saya sangat menyukai jawaban Zak dan dia telah mendapatkan inti dari masalah ini: eval digunakan ketika Anda menulis bahasa baru, naskah, atau modifikasi bahasa. Dia tidak benar-benar menjelaskan lebih lanjut jadi saya akan memberikan contoh:
Dalam program Lisp sederhana ini, pengguna diminta untuk input dan kemudian apa pun yang mereka masukkan dievaluasi. Agar ini bekerja secara keseluruhan rangkaian definisi simbol harus ada jika program dikompilasi, karena Anda tidak tahu fungsi yang dapat dimasukkan oleh pengguna, jadi Anda harus memasukkan semuanya. Itu berarti bahwa jika Anda mengkompilasi program sederhana ini, biner yang dihasilkan akan menjadi raksasa.
Pada prinsipnya, Anda bahkan tidak dapat menganggap ini sebagai pernyataan yang dapat dikompilasi karena alasan ini. Secara umum, setelah Anda menggunakan eval , Anda beroperasi di lingkungan yang ditafsirkan, dan kode tidak lagi dapat dikompilasi. Jika Anda tidak menggunakan eval maka Anda dapat mengkompilasi program Lisp atau Skema seperti program C. Oleh karena itu, Anda ingin memastikan bahwa Anda ingin dan perlu berada dalam lingkungan yang ditafsirkan sebelum berkomitmen untuk menggunakan eval .
sumber