Saya sedang menulis fungsi yang, pada prinsipnya, mengambil sejumlah argumen. Dalam prakteknya, bagaimanapun, harus hanya pernah melewati bahkan jumlah argumen, dan akan menghasilkan hasil yang tidak diinginkan sebaliknya.
Berikut ini contoh contoh untuk konteks:
(defun my-caller (&rest args)
(while args
(call-other-function (pop args) (pop args))))
Ketika file elisp dikompilasi dengan byte, byte-compiler memberikan peringatan ketika melihat fungsi dipanggil dengan jumlah argumen yang salah. Jelas, itu tidak akan pernah terjadi my-caller
, karena itu ditetapkan untuk mengambil nomor berapa pun.
Namun, mungkin ada properti simbol yang bisa saya atur, atau (declare)
bentuk yang bisa saya tambahkan ke definisinya. Sesuatu untuk memberi tahu pengguna bahwa fungsi ini seharusnya hanya diberikan sejumlah argumen.
- Apakah ada cara untuk menginformasikan byte-compiler tentang pembatasan ini?
- Jika tidak, Apakah mungkin dengan makro, alih-alih fungsi?
elisp
byte-compilation
Malabarba
sumber
sumber
Jawaban:
EDIT : Cara yang lebih baik untuk melakukan ini di Emacs baru-baru ini adalah dengan mendefinisikan makro kompiler untuk memeriksa jumlah argumen. Jawaban asli saya menggunakan makro normal dipertahankan di bawah ini, tetapi makro kompiler lebih unggul karena tidak mencegah melewatkan fungsi ke
funcall
atauapply
saat runtime.Di versi terbaru Emacs, Anda bisa melakukan ini dengan mendefinisikan kompiler-makro untuk fungsi Anda yang memeriksa jumlah argumen dan menghasilkan peringatan (atau bahkan kesalahan) jika tidak cocok. Satu-satunya kehalusan adalah bahwa makro kompiler harus mengembalikan bentuk panggilan fungsi asli tidak berubah untuk evaluasi atau kompilasi. Ini dilakukan dengan menggunakan
&whole
argumen dan mengembalikan nilainya. Ini bisa dicapai seperti ini:Catat itu
funcall
danapply
sekarang bisa digunakan, tetapi mereka mem-bypass pengecekan oleh kompiler makro. Meskipun nama mereka, macro compiler juga tampaknya akan diperluas dalam perjalanan 'ditafsirkan' evaluasi melalui C-xC-e, M-xeval-buffer, sehingga Anda akan mendapatkan kesalahan pada evaluasi serta pada kompilasi contoh ini.Jawaban asli berikut:
Inilah cara Anda menerapkan saran Jordon untuk "menggunakan makro yang akan memberikan peringatan pada waktu ekspansi". Ternyata sangat mudah:
Mencoba mengkompilasi hal di atas dalam file akan gagal (tidak ada
.elc
file yang dihasilkan), dengan pesan kesalahan yang dapat diklik bagus di kompilasi log, menyatakan:Anda juga dapat mengganti
(error …)
dengan(byte-compile-warn …)
untuk menghasilkan peringatan alih-alih kesalahan, memungkinkan kompilasi untuk melanjutkan. (Terima kasih kepada Jordon karena menunjukkan ini dalam komentar).Karena makro diperluas pada waktu kompilasi, tidak ada penalti waktu berjalan terkait dengan pemeriksaan ini. Tentu saja, Anda tidak dapat menghentikan panggilan orang lain
my-caller--function
secara langsung, tetapi setidaknya Anda dapat mengiklankannya sebagai fungsi "pribadi" menggunakan konvensi hyphen-double.Kerugian penting menggunakan makro untuk tujuan ini adalah bahwa
my-caller
tidak lagi fungsi kelas satu: Anda tidak bisa meneruskannya kefuncall
atauapply
saat runtime (atau setidaknya itu tidak akan melakukan apa yang Anda harapkan). Dalam hal itu, solusi ini tidak sebaik bisa dengan mudah mendeklarasikan peringatan kompiler untuk fungsi yang sebenarnya. Tentu saja, menggunakan tidakapply
akan memungkinkan untuk memeriksa jumlah argumen yang diteruskan ke fungsi pada waktu kompilasi, jadi mungkin ini merupakan trade-off yang dapat diterima.sumber
byte-compile-warn
apply
ataufuncall
pembungkus makro. Saya akan mencobanya dan mengedit jawaban saya jika berhasil.Ya, Anda dapat menggunakan
byte-defop-compiler
untuk benar-benar menentukan fungsi yang mengkompilasi fungsi Anda,byte-defop-compiler
memiliki beberapa fitur bawaan untuk membantu Anda menentukan bahwa fungsi Anda harus menghasilkan peringatan berdasarkan memiliki sejumlah argumen.Dokumentasi
Tambahkan bentuk-kompiler untuk FUNCTION. Jika fungsinya adalah simbol, maka variabel "byte-SYMBOL" harus memberi nama opcode yang akan digunakan. Jika fungsi adalah daftar, elemen pertama adalah fungsi dan elemen kedua adalah simbol bytecode. Elemen kedua mungkin nihil, artinya tidak ada opcode. COMPILE-HANDLER adalah fungsi yang digunakan untuk mengkompilasi byte-op ini, atau mungkin singkatan 0, 1, 2, 3, 0-1, atau 1-2. Jika nil, maka handlernya adalah "byte-compile-SYMBOL.
Pemakaian
Dalam kasus spesifik Anda, Anda dapat menggunakan salah satu singkatan untuk menentukan bahwa fungsi Anda harus diberikan dua argumen.
Sekarang fungsi Anda akan memberikan peringatan ketika dikompilasi dengan apa pun kecuali 2 argumen.
Jika Anda ingin memberikan peringatan yang lebih spesifik dan menulis fungsi kompiler Anda sendiri. Lihat
byte-compile-one-arg
dan fungsi serupa lainnya di bytecomp.el untuk referensi.Perhatikan bahwa Anda tidak hanya menentukan beberapa fungsi untuk menangani validasi, tetapi sebenarnya kompilasi juga. Sekali lagi kompilasi fungsi di bytecomp.el akan memberi Anda referensi yang bagus.
Rute yang Lebih Aman
Ini bukan sesuatu yang saya lihat didokumentasikan atau didiskusikan secara online tetapi secara keseluruhan saya akan mengatakan ini adalah rute yang salah untuk diambil. Rute yang benar (IMO) adalah untuk menulis pembelokan Anda dengan tanda tangan deskriptif atau menggunakan makro yang akan memberikan peringatan pada waktu ekspansi, memeriksa panjang argumen Anda dan menggunakan
byte-compile-warn
atauerror
untuk menunjukkan kesalahan. Mungkin juga bermanfaat bagi Andaeval-when-compile
untuk melakukan pengecekan kesalahan.Anda juga perlu mendefinisikan fungsi Anda sebelum digunakan, dan panggilan ke
byte-defop-compiler
harus sebelum kompilator mendapatkan panggilan sebenarnya dari fungsi Anda.Sekali lagi, sepertinya tidak benar-benar didokumentasikan atau dinasihati dari apa yang saya lihat (bisa saja salah) tapi saya membayangkan pola untuk mengikuti di sini adalah untuk menentukan beberapa jenis file header untuk paket Anda yang penuh dengan sekelompok pembelotan kosong dan panggilan ke
byte-defop-compiler
. Ini pada dasarnya akan menjadi paket yang diperlukan sebelum paket asli Anda dapat dikompilasi.Opini: Berdasarkan pada apa yang saya ketahui, yang tidak banyak, karena saya baru belajar tentang semua ini, saya akan menyarankan Anda untuk tidak melakukan semua ini. pernah
sumber