2016-11-22 3 views
9

पर पारित होने पर प्रो को निष्पादित किया जाता है प्रश्न यह प्रश्न this one से प्रेरित है। जिस स्थिति में है कि ब्लॉक Proc में बदल जाती है`instance_exec`

Proc::new केवल एक संलग्न ब्लॉक के साथ एक विधि के भीतर एक ब्लॉक के बिना कहा जा सकता है,:

Proc::new एक विकल्प के लिए एक विधि के अंदर एक ब्लॉक के बिना के नाम से जाना है वस्तु।

proc/lambda उदाहरण एक कोड ब्लॉक के रूप में पारित कर दिया जाता है, तो Proc का नया उदाहरण बन जाता है किया जा रहा:

Proc.singleton_class.prepend(Module.new do 
    def new(*args, &cb) 
    puts "PROC#{[block_given?, cb, *args].inspect}" 
    super 
    end 
end) 

Proc.prepend(Module.new do 
    def initialize(*args, &cb) 
    puts "INIT #{[block_given?, cb, *args].inspect}" 
    super 
    end 
    def call(*args, &cb) 
    puts "CALL #{[block_given?, cb, *args].inspect}" 
    super 
    end 
end) 

λ = ->(*args) { } 
[1].each &λ 
#⇒ [1] 

एक देख सकते हैं, न Proc::new करने के लिए कॉल हुआ, और न ही Proc#initialize और/या Proc#call कहा जाता था।

सवाल यह है: कैसे रूबी हुड के नीचे एक ब्लॉक रैपर बनाता है और निष्पादित करता है?


नायब में pry/irb सांत्वना ऊपर कोड का परीक्षण मत करो: वे इस बात का शुद्ध निष्पादन के साथ खामियों के लिए जाना जाता है, मूल रूप से, क्योंकि वे पैच procs।

+0

रूबी का संस्करण? – fl00r

+0

@ fl00r एमआरआई 2.1-2.3, मुझे वास्तव में विश्वास है कि सभी संस्करण यहां पर कार्य कर रहे हैं। – mudasobwa

+0

मैं आपका आउटपुट 'रूबी 2.2.2p95 (2015-04-13 संशोधन 50295) प्राप्त नहीं कर सकता [x86_64-darwin14] 'मुझे मिला [1]। प्रत्येक &λ; => [1]' – fl00r

उत्तर

2

रुबी अंक ट्रैकर पर इस व्यवहार की कुछ चर्चा हुई है, Feature #10499: Eliminate implicit magic in Proc.new and Kernel#proc देखें।

यह YARV का कार्यान्वयन कलाकृति है: YARV वैश्विक VM स्टैक पर एक ब्लॉक को धक्का देता है, और Proc::new बस स्टैक पर शीर्षतम ब्लॉक से Proc बनाता है। इसलिए, यदि आप किसी ब्लॉक के साथ बुलाए गए तरीके से Proc.new पर कॉल करना चाहते हैं, तो यह बिना किसी जांच के किए गए ब्लॉक के शीर्ष पर जो भी ब्लॉक है, उसे खुशी से पकड़ लेगा। किसी भी तरह, कहीं, समय की धुंध में, यह (चलो इसे कॉल करें) "आकस्मिक आर्टिफैक्ट" (मैं वास्तव में इसे एक बग कहूंगा) एक दस्तावेजी फीचर बन गया। एक विशेषता है कि जेआरबीई के डेवलपर्स (और संभवतः रूबिनीस, ओपल, मैग्लेव इत्यादि) इससे छुटकारा पायेंगे।

चूंकि ज्यादातर अन्य कार्यान्वयन पूरी तरह से अलग तरह से काम, इस व्यवहार जो YARV पर "मुक्त करने के लिए" आता है, दोनों ब्लॉक और Proc::new pontetially अधिक अन्य कार्यान्वयन पर महंगा है और प्रतिबंध लगाता संभव अनुकूलन (जो YARV पर चोट नहीं करता है बनाता है क्योंकि YARV नहीं करता है अनुकूलन नहीं है)।

+0

"YARV VM स्टैक पर ब्लॉक में एक पॉइंटर को धक्का देता है" - यह मेरे प्रश्न के उत्तर के आधे से ज्यादा दिखता है। क्या इसका मतलब यह है कि 1) किसी अन्य रूबी कार्यान्वयन को '[1]। एच और λ' और 2 के लिए 'प्रो :: नया' कहते हैं) डेवलपर के पास वाईएआरवी में '[1]। एच और λ' हस्तक्षेप करने की कोई क्षमता नहीं है, क्योंकि वहां है कोई 'प्रो' उदाहरण बिल्कुल बनाया गया नहीं है?AFAIU, क्या स्टैक में "पहले से बाहर" के रूप में एक ब्लॉक शामिल होता है, यारव खुशी से किसी भी अन्य रूबी कोड/रैपर/जो भी हो, उसे सही तरीके से निष्पादित करेगा? – mudasobwa

+0

सुनिश्चित नहीं है। मेरा जवाब चार्ल्स न्यूटर द्वारा एक-पंक्ति पोस्ट की एक अस्पष्ट स्मृति पर आधारित था, जिसे मैंने अब पाया और मेरे जवाब में लिंक किया। हालांकि, यह समझाया नहीं गया है कि कैसे JRuby यह करता है। –

+0

समझ गया, धन्यवाद। यदि आपके पास अपना जवाब अपडेट किया गया है तो मैं सराहना करता हूं "विधि में गुज़रने वाले ब्लॉक में हस्तक्षेप करने के लिए जो भी समाधान लागू किया जा सकता है, यह क्रॉस-वीएम कार्यान्वयन प्रतीत नहीं होता है।" – mudasobwa

संबंधित मुद्दे