मेटाप्रोग्रामिंग एक बहुत ही फैंसी शब्द की तरह लगता है, लेकिन क्या यह अच्छा है?
यह उपयोगी हो सकता है, लेकिन बहुत से लोग यह नहीं समझते हैं कि मेटाप्रोग्रामिंग का उपयोग करने की कुछ लागतें हैं।
ठीक वैसे ही हम एक ही पृष्ठ पर हैं…
मेटाप्रोग्रामिंग क्या है बिल्कुल?
मैं मेटाप्रोग्रामिंग को किसी भी विधि का उपयोग करने के रूप में परिभाषित करता हूं:
- आपके कोड की संरचना को बदल देता है (जैसे
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
, या आपके संपादक को विधि परिभाषाओं की खोज करने के लिए, मेटाप्रोग्रामिंग विधियों को खोजना कठिन होगा नियमित तरीकों की तुलना में।
"मुझे नहीं लगता कि साइडकीक किसी मेटाप्रोग्रामिंग . का उपयोग करता है बिल्कुल भी क्योंकि मुझे लगता है कि यह 95% समय की तुलना में अधिक कोड को अस्पष्ट करता है।" - माइक परहम, साइडकीक के निर्माता
निष्कर्ष
मेटाप्रोग्रामिंग के बारे में सब कुछ बुरा नहीं है। यह आपके कोड को अधिक लचीला बनाने के लिए सही परिस्थितियों में उपयोगी हो सकता है।
बस अतिरिक्त लागतों से अवगत रहें ताकि आप बेहतर निर्णय ले सकें।
इस पोस्ट को शेयर करना न भूलें अगर आपको यह उपयोगी लगा 🙂