मेटाप्रोग्रामिंग बहुत फैंसी शब्द लगता है, लेकिन क्या यह अच्छा है?
यह उपयोगी हो सकता है, लेकिन बहुत से लोग यह नहीं समझते कि मेटाप्रोग्रामिंग का उपयोग करने की कुछ लागतें हैं।
बस ताकि हम एक ही पेज पर हों...
मेटाप्रोग्रामिंग वास्तव में क्या है?
मैं मेटाप्रोग्रामिंग को किसी भी मेथड का उपयोग करने के रूप में परिभाषित करता हूं जो:
- आपके कोड की संरचना को बदलता है (जैसे
define_method) - स्ट्रिंग को चलाता है जैसे कि यह आपके वास्तविक रूबी कोड का हिस्सा था (जैसे
instance_eval) - किसी घटना की प्रतिक्रिया के रूप में कुछ करता है (जैसे
method_missing)
तो मेटाप्रोग्रामिंग की लागतें क्या हैं? मैं उन्हें 3 समूहों में वर्गीकृत करता हूं:
- गति
- पठनीयता
- खोजने योग्यता
नोट: आप यह भी कह सकते हैं कि चौथा समूह है: सुरक्षा. इसका कारण
evalमेथड्स हैं, जो पास की जा रही चीज़ पर किसी भी प्रकार की सुरक्षा जांच नहीं करते। आपको इसे स्वयं करना होगा।
आइए उनमें से प्रत्येक को विस्तार से जानें!
गति
पहली लागत गति है क्योंकि अधिकांश मेटाप्रोग्रामिंग मेथड्स नियमित मेथड्स की तुलना में धीमे होते हैं।
यहां कुछ बेंचमार्किंग कोड है:
require 'benchmark/ips' class Thing def method_missing(name, *args) end def normal_method end define_method(:speak) {} end t = Thing.new Benchmark.ips do |x| x.report("normal method") { t.normal_method } x.report("missing method") { t.abc } x.report("defined method") { t.speak } x.compare! end परिणाम (रूबी 2.2.4):
normal method: 7344529.4 i/s defined method: 5766584.9 i/s - 1.34x slower missing method: 4777911.7 i/s - 1.54x slower
जैसा कि आप देख सकते हैं दोनों मेटाप्रोग्रामिंग मेथड्स (define_method और method_missing) नियमित मेथड की तुलना में काफी धीमे हैं।
यहां कुछ दिलचस्प है जो मैंने खोजा...
उपरोक्त परिणाम Ruby 2.2.4 से हैं, लेकिन यदि आप इन बेंचमार्क को Ruby 2.3 या Ruby 2.4 पर चलाते हैं तो ऐसा लगता है कि ये मेथड्स और धीमे हो रहे हैं!
रूबी 2.4 बेंचमार्क परिणाम:
normal method: 8252851.6 i/s defined method: 6153202.9 i/s - 1.39x slower missing method: 4557376.3 i/s - 1.87x slower
मैंने यह बेंचमार्क कई बार चलाया ताकि यह सुनिश्चित हो सके कि यह कोई अस्थायी नहीं था।
लेकिन यदि आप ध्यान दें और प्रति सेकंड पुनरावृत्तियों (i/s) को देखें तो ऐसा लगता है कि रूबी 2.3 के बाद से नियमित मेथड्स तेज़ हो गए हैं। यही कारण है कि method_missing बहुत धीमा दिखता है 🙂
पठनीयता
instance_eval / class_eval मेथड्स का उपयोग करते समय त्रुटि संदेश कम सहायक हो सकते हैं।
निम्नलिखित कोड पर एक नज़र डालें:
class Thing class_eval("def self.foo; raise 'something went wrong'; end") end Thing.foo इसके परिणामस्वरूप निम्न त्रुटि होगी:
(eval):1:in 'foo': 'something went wrong...' (RuntimeError)
ध्यान दें कि फ़ाइल नाम गायब है (यह eval कहता है) और सही लाइन नंबर। अच्छी खबर यह है कि इसके लिए एक समाधान है, ये eval मेथड्स दो अतिरिक्त पैरामीटर लेते हैं:
- एक फ़ाइल नाम
- एक लाइन नंबर
बिल्ट-इन कॉन्स्टेंट्स __FILE__ और __LINE__ को class_eval के पैरामीटर के रूप में उपयोग करके आपको त्रुटि संदेश में सही जानकारी मिलेगी।
उदाहरण:
class Thing class_eval( "def foo; raise 'something went right'; end", __FILE__, __LINE__ ) end
यह डिफ़ॉल्ट क्यों नहीं है?
मुझे नहीं पता, लेकिन यह कुछ ऐसा है जिसे ध्यान में रखना चाहिए यदि आप इन मेथड्स का उपयोग करने जा रहे हैं 🙂
खोजने योग्यता
मेटाप्रोग्रामिंग मेथड्स आपके कोड को कम खोजने योग्य, कम सुलभ (खराब दस्तावेज़ीकरण के माध्यम से) और डिबग करना कठिन बनाते हैं।
यदि आप किसी मेथड परिभाषा की तलाश कर रहे हैं तो आप मेटाप्रोग्रामिंग के माध्यम से परिभाषित मेथड को खोजने के लिए CTRL+F (या आप जिस भी शॉर्टकट का उपयोग करते हैं) नहीं कर पाएंगे, खासकर यदि मेथड का नाम रन-टाइम पर बनाया गया है।
निम्नलिखित उदाहरण मेटाप्रोग्रामिंग का उपयोग करके 3 मेथड्स परिभाषित करता है:
class RubyBlog def create_post_tags types = ['computer_science', 'tools', 'advanced_ruby'] types.each do |type| define_singleton_method(type + "_tag") { puts "This post is about #{type}" } end end end rb = RubyBlog.new rb.create_post_tags rb.computer_science_tag दस्तावेज़ीकरण उत्पन्न करने वाले टूल्स (जैसे Yard या RDoc) इन मेथड्स को ढूंढ और सूचीबद्ध नहीं कर सकते।
ये टूल्स क्लासेस और मेथड्स को खोजने के लिए "स्टेटिक एनालिसिस" नामक तकनीक का उपयोग करते हैं। यह तकनीक केवल उन मेथड्स को ढूंढ सकती है जो सीधे परिभाषित हैं (def सिंटैक्स का उपयोग करके)।
पिछले उदाहरण के साथ yard doc चलाने का प्रयास करें, आप देखेंगे कि पाया गया एकमात्र मेथड create_post_tags है।
यह ऐसा दिखता है:

yard को अतिरिक्त मेथड्स दस्तावेज़ करने के लिए बताने का एक तरीका है, @method टैग का उपयोग करके, लेकिन यह हमेशा व्यावहारिक नहीं होता।
उदाहरण:
class Thing # @method build_report define_method(:build_report) end
इसके अलावा यदि आप grep, ack, या अपने संपादक जैसे टूल का उपयोग करके मेथड परिभाषाओं की खोज करने जा रहे हैं, मेटाप्रोग्रामिंग मेथड्स को ढूंढना नियमित मेथड्स की तुलना में कठिन होगा।
"मुझे नहीं लगता कि Sidekiq किसी मेटाप्रोग्रामिंग का उपयोग करता है क्योंकि मुझे लगता है कि यह 95% समय कोड को अस्पष्ट करता है जितना यह मदद करता है।" - माइक पेरहैम, Sidekiq के निर्माता
निष्कर्ष
मेटाप्रोग्रामिंग के बारे में सब कुछ बुरा नहीं है। सही स्थितियों में यह आपके कोड को अधिक लचीला बनाने के लिए उपयोगी हो सकता है।
बस अतिरिक्त लागतों के बारे में जागरूक रहें ताकि आप बेहतर निर्णय ले सकें।
इस पोस्ट को शेयर करना न भूलें अगर आपको यह उपयोगी लगा 🙂