क्या कोई फ़ंक्शन या मैक्रो बाइट-कंपाइलर चेतावनी को निर्दिष्ट कर सकता है?


15

मैं एक फ़ंक्शन लिख रहा हूं, जो सिद्धांत रूप में, एक मनमानी संख्या लेता है। व्यवहार में, हालांकि, यह केवल कभी एक पारित किया जाना चाहिए भी तर्क की संख्या, और अन्यथा अवांछनीय परिणाम देगा।

यहाँ संदर्भ के लिए एक डमी उदाहरण है:

(defun my-caller (&rest args)
  (while args
    (call-other-function (pop args) (pop args))))

जब एक क्विक फ़ाइल बाइट-संकलित होती है, तो बाइट-कंपाइलर एक चेतावनी फेंकता है जब यह देखता है कि फ़ंक्शन गलत तर्कों के साथ लाया जा रहा है। जाहिर है, यह कभी नहीं होने वाला है my-caller, क्योंकि यह किसी भी संख्या को लेने के लिए परिभाषित है।

फिर भी, शायद एक प्रतीक संपत्ति है जिसे मैं सेट कर सकता हूं, या एक ऐसा (declare)रूप जो मैं इसकी परिभाषा में जोड़ सकता हूं। उपयोगकर्ता को सूचित करने के लिए कुछ कि इस फ़ंक्शन को केवल तर्कों की संख्या दी जानी चाहिए।

  1. क्या इस प्रतिबंध के बाइट-कंपाइलर को सूचित करने का कोई तरीका है?
  2. यदि नहीं, तो क्या यह फ़ंक्शन के बजाय मैक्रो के साथ संभव है?

"... जब यह देखता है कि किसी फ़ंक्शन को गलत संख्या में तर्क दिए जा रहे हैं"?
इसका अजायबघर

जवाबों:


13

संपादित करें : हाल के Emacs में ऐसा करने का एक बेहतर तरीका है कि तर्कों की संख्या की जांच करने के लिए एक संकलक मैक्रो को परिभाषित करना । सामान्य मैक्रो का उपयोग करके मेरा मूल उत्तर नीचे संरक्षित है, लेकिन एक संकलक-मैक्रो बेहतर है क्योंकि यह फ़ंक्शन को रनटाइम पर funcallया पास करने से नहीं रोकता applyहै।

Emacs के हाल के संस्करणों में, आप अपने फ़ंक्शन के लिए एक कंपाइलर-मैक्रो को परिभाषित करके ऐसा कर सकते हैं जो तर्कों की संख्या की जांच करता है और अगर यह मेल नहीं खाता है तो एक चेतावनी (या एक त्रुटि) भी पैदा करता है। एकमात्र सूक्ष्मता यह है कि संकलक मैक्रो को मूल फ़ंक्शन कॉल फॉर्म को मूल्यांकन या संकलन के लिए अपरिवर्तित वापस करना चाहिए। यह एक &wholeतर्क का उपयोग करके और उसके मूल्य को वापस करने के द्वारा किया जाता है । इसे इस तरह पूरा किया जा सकता है:

(require 'cl-lib)

(defun my-caller (&rest args)
  (while args
    (message "%S %S" (pop args) (pop args))))

(define-compiler-macro my-caller (&whole form &rest args)
  (when (not (cl-evenp (length args)))
    (byte-compile-warn "`my-caller' requires an even number of arguments"))
  form)

(my-caller 1 2 3 4)
(my-caller 1 2)
(funcall #'my-caller 1 2 3 4)       ; ok
(apply #'my-caller '(1 2))          ; also ok
(my-caller 1)                       ; produces a warning
(funcall #'my-caller 1 2 3)         ; no warning!
(apply #'my-caller '(1 2 3))        ; also no warning

ध्यान दें कि funcallऔर applyअब इस्तेमाल किया जा सकता है, लेकिन वे संकलक मैक्रो द्वारा तर्क की जाँच को बायपास करते हैं। उनके नाम के बावजूद, संकलक मैक्रो भी मूल्यांकन के 'व्याख्या' पाठ्यक्रम के माध्यम से में विस्तार किया जा करने लगते हैं C-xC-e, M-xeval-bufferहै, तो आप का मूल्यांकन करने के साथ-साथ इस उदाहरण संकलन पर त्रुटियों मिल जाएगा।


मूल उत्तर इस प्रकार है:

यहां बताया गया है कि आप "मैक्रो का उपयोग करने के लिए जॉर्डन के सुझाव को कैसे लागू कर सकते हैं जो विस्तार के समय चेतावनी प्रदान करेगा"। यह बहुत आसान है:

(require 'cl-lib)

(defmacro my-caller (&rest args)
  (if (cl-evenp (length args))
      `(my-caller--function ,@args)
    (error "Function `my-caller' requires an even number of arguments")))

(defun my-caller--function (&rest args)
  ;; function body goes here
  args)

(my-caller 1 2 3 4)
(my-caller 1 2 3)

संकलन .elcफ़ाइल में एक अच्छा क्लिक करने योग्य त्रुटि संदेश के साथ, एक फ़ाइल में उपरोक्त संकलन करने की कोशिश विफल हो जाएगी (कोई फ़ाइल का उत्पादन नहीं होता है):

test.el:14:1:Error: `my-caller' requires an even number of arguments

तुम भी बदल सकते (error …)के साथ (byte-compile-warn …)एक त्रुटि के बजाय एक चेतावनी के उत्पादन के लिए, जारी रखने के लिए संकलन की इजाजत दी। (टिप्पणियों में इसे इंगित करने के लिए जॉर्डन के लिए धन्यवाद)।

चूंकि मैक्रोज़ का संकलन समय पर विस्तार किया गया है, इसलिए इस चेक के साथ कोई रन-टाइम जुर्माना नहीं जुड़ा है। बेशक, आप my-caller--functionसीधे कॉल करने वाले अन्य लोगों को रोक नहीं सकते हैं, लेकिन आप कम से कम इसे डबल-हाइफ़न सम्मेलन का उपयोग करके "निजी" फ़ंक्शन के रूप में विज्ञापित कर सकते हैं।

एक उल्लेखनीय नुकसान इस उद्देश्य के लिए मैक्रो का उपयोग का है my-callerअब एक प्रथम श्रेणी के समारोह है: आप इसे करने के लिए पारित नहीं हो सकता funcallया applyकार्यावधि में (या कम से कम यह आप क्या उम्मीद नहीं करेंगे)। उस संबंध में, यह समाधान केवल एक वास्तविक कार्य के लिए संकलक चेतावनी घोषित करने में सक्षम होने के रूप में काफी अच्छा नहीं है। बेशक, इसका उपयोग करके applyकिसी भी समय संकलन-समय पर फ़ंक्शन को दिए जा रहे तर्कों की संख्या की जांच करना असंभव हो जाएगा, इसलिए शायद यह स्वीकार्य व्यापार-बंद है।


2
संकलन चेतावनी के साथ बनाई गई हैंbyte-compile-warn
जॉर्डन बियोनडो

मुझे अब आश्चर्य है कि क्या यह फ़ंक्शन के लिए एक संकलक मैक्रो को परिभाषित करके अधिक प्रभावी ढंग से पूरा किया जा सकता है। यह मैक्रो रैपर applyया नहीं होने के नुकसान को खत्म करेगा funcall। यदि यह काम करता है तो मैं इसे आज़माऊंगा और अपना उत्तर संपादित करूंगा।
जॉन ओ।

11

हां, आप byte-defop-compilerवास्तव में एक फ़ंक्शन को निर्दिष्ट करने के लिए उपयोग कर सकते हैं जो आपके फ़ंक्शन को संकलित करता है, byte-defop-compilerकुछ ने यह सुनिश्चित करने में मदद करने के लिए कि आपके फ़ंक्शन को कई आर्ग के आधार पर चेतावनियों का उत्पादन करना चाहिए , में निर्मित किया है।

प्रलेखन

FUNCTION.If फ़ंक्शन के लिए एक कंपाइलर-फ़ॉर्म जोड़ें, जो एक प्रतीक है, फिर चर "बाइट-सिम्बोल" का उपयोग करने के लिए ओपकोड को नाम देना होगा। यदि फ़ंक्शन एक सूची है, तो पहला तत्व फ़ंक्शन है और दूसरा तत्व बाइटकोड-प्रतीक है। दूसरा तत्व शून्य हो सकता है, जिसका अर्थ है कि कोई ओपकोड नहीं है। Compile-HANDLER इस बाइट-ऑप को संकलित करने के लिए उपयोग करने वाला फ़ंक्शन है, या संक्षिप्त रूप 0, 1, 2, 3, 0-1, या 1-2 हो सकता है। यदि यह शून्य है, तो हैंडलर "बाइट-कंपाइल-सिम्बोल" है।


प्रयोग

अपने विशिष्ट मामले में आप यह परिभाषित करने के लिए किसी एक संक्षिप्ताक्षर का उपयोग कर सकते हैं कि आपके फ़ंक्शन को दो आर्ग दिए जाने चाहिए।

(byte-defop-compiler my-caller 2)

अब आप कार्य कर रहे हैं चेतावनियाँ जब कुछ के साथ संकलित किया जाएगा, लेकिन 2 args।

यदि आप अधिक विशिष्ट चेतावनियाँ देना चाहते हैं और अपने स्वयं के संकलक कार्य लिखना चाहते हैं। पर देखो byte-compile-one-argऔर संदर्भ के लिए bytecomp.el में अन्य इसी तरह के कार्य करता है।

ध्यान दें कि आप सत्यापन को संभालने के लिए केवल कुछ फ़ंक्शन को निर्दिष्ट नहीं कर रहे हैं, लेकिन वास्तव में संकलन भी। Bytecomp.el में फिर से संकलन कार्य आपको एक अच्छा संदर्भ प्रदान करेगा।


सुरक्षित मार्गों

यह कुछ ऐसा नहीं है जिसे मैंने ऑनलाइन देखा या चर्चा की है, लेकिन कुल मिलाकर मैं यह कहूंगा कि इसे लेने के लिए एक मार्ग की सलाह दी जाती है। सही मार्ग (IMO) वर्णनात्मक हस्ताक्षरों के साथ आपके दोषों को लिखना होगा या एक मैक्रो का उपयोग करना होगा जो विस्तार के समय पर चेतावनी प्रदान करेगा, आपके आर्गों की लंबाई की जांच करेगा और त्रुटियों का उपयोग करेगा byte-compile-warnया errorदिखाएगा। eval-when-compileत्रुटि जाँच करने के लिए इसका उपयोग करने से आपको लाभ हो सकता है ।

आपके फ़ंक्शन को कभी भी उपयोग किए जाने से पहले आपको परिभाषित करने byte-defop-compilerकी आवश्यकता होगी , और कंपाइलर को आपके फ़ंक्शन की वास्तविक कॉल करने से पहले कॉल करने की आवश्यकता होगी।

फिर, लगता है कि वास्तव में दस्तावेज नहीं है या जो मैंने देखा है (गलत हो सकता है) से सलाह दी गई है, लेकिन मुझे लगता है कि यहां अनुसरण करने के लिए पैटर्न आपके पैकेज के लिए किसी प्रकार की हेडर फ़ाइल को निर्दिष्ट करने के लिए होगा जो खाली डिफंस के एक गुच्छा से भरा है। और को कॉल करता है byte-defop-compiler। यह मूल रूप से एक पैकेज होगा जो आपके असली पैकेज को संकलित करने से पहले आवश्यक है।

राय: मैं जो जानता हूं, उसके आधार पर, जो कि बहुत अधिक नहीं है, क्योंकि मैंने सिर्फ इस सब के बारे में सीखा है, मैं आपको सलाह दूंगा कि आप कभी भी ऐसा न करें। कभी


1
संबंधित: बाइटेकॉम्प-सरलीकरण है जो बाइट-कंपाइलर अतिरिक्त चेतावनी सिखाता है।
विल्फ्रेड ह्यूजेस
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.