7

यदि आप एरिक लिपर्ट द्वारा इस video में लगभग 13 मिनट तक आगे बढ़ते हैं तो वह सी # कंपाइलर में किए गए परिवर्तन का वर्णन करता है जो निम्नलिखित कोड को अमान्य (स्पष्ट रूप से पहले और सहित) प्रस्तुत करता है। नेट 2 यह कोड संकलित होगा)।स्थिरता और संकलन समय मूल्यांकन - इस व्यवहार को क्यों बदलें

int y; 
int x = 10; 
if (x * 0 == 0) 
    y = 123; 

Console.Write(y); 

अब मैं समझता हूँ कि स्पष्ट रूप से ऊपर कोड के किसी भी निष्पादन वास्तव में

int y; 
int x = 10; 
y = 123; 
Console.Write(y); 

का आकलन करती लेकिन मैं क्या न समझ में क्यों यह इन-compilable निम्नलिखित कोड बनाने के लिए माना जाता है "वांछनीय"? आईई: इस तरह के सम्मेलनों को अपना कोर्स चलाने की अनुमति देने के जोखिम क्या हैं?

+1

जिस तरह से मैं इसे समझता हूं, एरिक कह रहा है कि यह विनिर्देश के अनुपालन में संकलक के व्यवहार को लाने के लिए मुख्य रूप से (यदि विशेष रूप से नहीं) तय किया गया था। –

+0

@ कोडीग्रे, मुझे लगता है कि सवाल यह था कि यह विनिर्देशन में क्यों है। – mowwwalker

+0

@ वाल्कर्नियो - स्पॉट ऑन। मैं समझता हूं कि परिवर्तन क्यों किया गया था (जैसे एरिक ने समझाया) लेकिन मुझे नहीं पता कि यह पहले स्थान पर क्यों है। हालांकि तर्कसंगत रूप से अवांछित यह मेरे दिमाग में बयानों की वैध श्रृंखला है। –

उत्तर

8

मुझे अभी भी इस सवाल को थोड़ा उलझन में मिल रहा है लेकिन मुझे यह देखने दो कि क्या मैं इस प्रश्न को एक ऐसे रूप में दोहरा सकता हूं जिसे मैं उत्तर दे सकता हूं।

सी # 2.0 में, इस कोड:

int x = 123; 
int y; 
if (x * 0 == 0) 
    y = 345; 
Console.WriteLine(y); 

इलाज किया गया था जैसे कि आप लिखा था

int x = 123; 
int y; 
if (true) 
    y = 345; 
Console.WriteLine(y); 

बारी में है जो सबसे पहले, चलो मुझे फिर से राज्य सवाल की पृष्ठभूमि के रूप में माना जाता है:

int x = 123; 
int y; 
y = 345; 
Console.WriteLine(y); 

एक कानूनी कार्यक्रम कौन सा है।

लेकिन सी # 3.0 में हमने इसे रोकने के लिए ब्रेकिंग बदलाव लिया। इस तथ्य के बावजूद संकलक अब "हमेशा सत्य" होने के रूप में इस स्थिति का इलाज नहीं करता है कि आप और मैं दोनों जानते हैं कि यह हमेशा सत्य है। अब हम इसे एक अवैध कार्यक्रम बनाते हैं, क्योंकि संकलक के कारण यह नहीं जानता है कि "अगर" का शरीर हमेशा निष्पादित होता है, और इसलिए यह नहीं पता कि स्थानीय चर वाई को हमेशा इस्तेमाल होने से पहले असाइन किया जाता है।

सी # 3.0 व्यवहार सही क्यों है?

यह क्योंकि विनिर्देश कहा गया है कि सही है:

  • एक निरंतर अभिव्यक्ति केवल स्थिरांक शामिल होना चाहिए। x * 0 == 0 निरंतर अभिव्यक्ति नहीं है क्योंकि इसमें एक गैर-निरंतर शब्द, x है।

  • if का परिणाम केवल true के बराबर स्थिर अभिव्यक्ति है, तो केवल हमेशा पहुंचने योग्य माना जाता है।

इसलिए, दिए गए सशर्त बयान के परिणाम को वर्गीकृत नहीं किया जाना चाहिए कोड हमेशा पहुंच योग्य होने के लिए, और इसलिए निश्चित रूप से निर्धारित किये जाने के रूप में स्थानीय y वर्गीकृत नहीं करना चाहिए।

यह वांछनीय क्यों है कि निरंतर अभिव्यक्ति में केवल स्थिरांक होते हैं?

हम चाहते हैं कि सी # भाषा अपने उपयोगकर्ताओं द्वारा स्पष्ट रूप से समझने योग्य हो और संकलक लेखकों द्वारा सही ढंग से कार्यान्वित करने योग्य हो। यह आवश्यक है कि संकलक उन लक्ष्यों के खिलाफ अभिव्यक्ति के मूल्यों के बारे में सभी संभावित तार्किक कटौती करता है। यह निर्धारित करने के लिए सरल होना चाहिए या नहीं, और यदि हां, तो इसका मूल्य क्या है।बस रखें, निरंतर मूल्यांकन कोड को अंकगणित करने के लिए पता होना चाहिए, लेकिन तथ्यों अंकगणितीय जोड़ों के बारे में जानने की आवश्यकता नहीं है। निरंतर मूल्यांकनकर्ता कैसे 2 * 1 गुणा करने के लिए जानता है, लेकिन तथ्य को जानने की आवश्यकता नहीं है कि "1 पूर्णांक पर गुणक पहचान है"।

अब, यह संभव है कि एक कंपाइलर लेखक तय कर सकता है कि ऐसे क्षेत्र हैं जहां वे चालाक हो सकते हैं, और इस प्रकार अधिक इष्टतम कोड उत्पन्न करते हैं। कंपाइलर लेखकों को ऐसा करने की अनुमति है, लेकिन इस तरह से नहीं है कि कोड कानूनी या अवैध है। उन्हें केवल अनुकूलन करने की अनुमति है कि कानूनी कोड दिए जाने पर संकलक के आउटपुट को बेहतर बनाते हैं।

सी # 2.0 में बग कैसे हुआ?

क्या हुआ था कि गणित को अंकगणित अनुकूलक को बहुत जल्दी चलाने के लिए लिखा गया था। ऑप्टिमाइज़र थोड़ा सा चालाक माना जाता है, और के बाद इसे चलाने के लिए निर्धारित किया जाना चाहिए था। यह से पहले चल रहा था, कार्यक्रम कानूनी होने के लिए निर्धारित किया गया था, और इसलिए परिणाम को प्रभावित कर रहा था।

यह एक संभावित तोड़ने वाला परिवर्तन था: हालांकि यह संकलक को विनिर्देश के साथ लाइन में लाया, लेकिन यह संभावित रूप से कोड कोड को त्रुटि कोड में बदल गया। परिवर्तन में क्या प्रेरित हुआ?

LINQ सुविधाएं, और विशेष रूप से अभिव्यक्ति पेड़। यदि आप कुछ तरह ने कहा:

(int x)=>x * 0 == 0 

और एक अभिव्यक्ति पेड़ में बदल जाती है कि, आप पाएंगे कि

(int x)=>true 

के लिए अभिव्यक्ति पेड़ उत्पन्न करने के लिए उम्मीद करते हैं? शायद ऩही! आप शायद यह अभिव्यक्ति पेड़ का उत्पादन करने के लिए "शून्य से x गुणा करें और परिणाम की तुलना शून्य से करें"। अभिव्यक्ति के पेड़ों को शरीर में अभिव्यक्ति की तार्किक संरचना को संरक्षित रखना चाहिए।

जब मैं अभिव्यक्ति पेड़ कोड लिखा था यह अभी तक कि क्या डिजाइन समिति तय करने के लिए

()=>2 + 3 

"तीन को दो जोड़ने के लिए" अभिव्यक्ति पेड़ या अभिव्यक्ति उत्पन्न करने के लिए जा रहा था जा रहा था स्पष्ट नहीं था "पांच" के लिए पेड़। हमने बाद में निर्णय लिया - स्थिरांक पेड़ उत्पन्न होने से पहले फ़ोल्ड किए गए हैं, लेकिन अभिव्यक्ति पेड़ उत्पन्न होने से पहले अंकगणित के माध्यम से अंकगणित नहीं किया जाना चाहिए।

तो, चलो अब निर्भरता कि हम सिर्फ कहा गया है पर विचार करें:

  • अंकगणित अनुकूलन codegen से पहले होता है।
  • अभिव्यक्ति पेड़ नए सिरे से लिखना अंकगणित अनुकूलन
  • लगातार तह अभिव्यक्ति पेड़ को फिर से लिखने
  • लगातार तह
  • फ्लो विश्लेषण प्रवाह विश्लेषण से पहले होना होता है अभिव्यक्ति पेड़ को फिर से लिखने से पहले होना होता है से पहले होना होता है से पहले होना होता है (क्योंकि हम यह जानने की आवश्यकता है कि क्या एक अभिव्यक्ति वृक्ष एक अनियमित स्थानीय का उपयोग करता है)

हमें उन सभी निर्भरताओं को सम्मानित करने के लिए इस काम को करने का आदेश मिलना होगा। सी # 2.0 में संकलक इस क्रम में उन्हें क्या किया: एक ही समय में

  • निरंतर तह और गणित अनुकूलन
  • प्रवाह विश्लेषण
  • codegen

कहाँ अभिव्यक्ति पेड़ पुनर्लेखन कर सकते हैं में वहाँ जाना? कहीं भी नहीं! और स्पष्ट रूप से यह छोटी है, क्योंकि प्रवाह विश्लेषण अब अंकगणित अनुकूलक द्वारा निर्धारित तथ्यों को ध्यान में रख रहा है। हम संकलक rework करने का फैसला किया है ताकि यह क्रम में बातें किया:

  • निरंतर तह
  • प्रवाह विश्लेषण
  • अभिव्यक्ति पेड़ को फिर से लिखने
  • अंकगणित अनुकूलन
  • codegen

कौन सा स्पष्ट रूप से तोड़ने के बदलाव की जरुरत है।

  • निरंतर तह
  • अंकगणित अनुकूलन
  • प्रवाह विश्लेषण
  • अंकगणित de-अनुकूलन
  • अभिव्यक्ति पेड़ नए सिरे से लिखना:

    अब, मैं मौजूदा टूटा व्यवहार संरक्षण, ऐसा करके पर विचार किया

  • अंकगणित अनुकूलन फिर से
  • कोडजन

जहां अनुकूलित अंकगणितीय अभिव्यक्ति में पॉइंटर को अपने अपरिवर्तित रूप में वापस रखा जाएगा। हमने फैसला किया कि को बग को सुरक्षित रखने के लिए यह बहुत जटिलता थी। हमने फैसला किया कि बग को ठीक करने के लिए बेहतर होगा, ब्रेकिंग चेंज लें, और कंपाइलर आर्किटेक्चर को आसानी से समझें।

+0

एरिक, आप इस विषय पर अपने ब्लॉग पोस्ट को लिंक करना चाह सकते हैं: सभी बुराई भाग 1: http://blogs.msdn.com/b/ericlippert/archive/2006/03/28/the-root-of- all-evil-part-one.aspx भाग - 2: http://blogs.msdn.com/b/ericlippert/archive/2006/03/29/the-root-of-all-evil-part-two.aspx – SolutionYogi

+0

क्या मैं बस इतना कह सकता हूं कि मेरे जैसे प्रश्नों का उत्तर देने के लिए समय निकालने के लिए धन्यवाद और इस तरह के एक अद्भुत उत्पाद को बनाने में भी मदद करें। इसकी ईमानदारी से सराहना की। –

3

विनिर्देश बताता है कि किसी चीज का निश्चित असाइनमेंट जिसे केवल if ब्लॉक के अंदर असाइन किया गया है, अनिश्चित है। स्पेक कंपाइलर जादू के बारे में कुछ भी नहीं कहता है जो अनावश्यक if ब्लॉक को हटा देता है। विशेष रूप से, यह बहुत ही भ्रमित त्रुटि संदेश बनाता है क्योंकि आप if स्थिति बदलते हैं, और अचानक y को असाइन नहीं किया जा रहा है, "हू? जब मैंने असाइन किया है तो मैंने नहीं बदला है!"।

संकलक किसी भी स्पष्ट कोड को निष्पादित करने के लिए स्वतंत्र है, लेकिन पहले इसे नियमों के लिए विनिर्देशों का पालन करना होगा।

विशेष रूप से, खंड 5.3.3.5 (एमएस 4.0 कल्पना):

5.3.3.5 तो बयान फार्म की एक अगर बयान stmt के लिए:

if (expr)तत्कालीन stmtelseबाकी-stmt

  • वी में एसएमटी की शुरुआत में एक्सप्रप्रस की शुरुआत में एक ही निश्चित असाइनमेंट स्टेटस है।
  • यदि वी निश्चित रूप से एक्सप्रो के अंत में असाइन किया गया है, तो यह निश्चित रूप से नियंत्रण प्रवाह हस्तांतरण पर तब-एसएमएमटी और किसी और के लिए या stmt के अंत बिंदु पर असाइन किया गया है यदि कोई और खंड नहीं है।
  • यदि वी के पास एक्सप्रप्रो के अंत में "निश्चित अभिव्यक्ति के बाद निश्चित रूप से असाइन किया गया" है, तो यह निश्चित रूप से नियंत्रण प्रवाह हस्तांतरण पर तत्काल निर्धारित किया जाता है, और निश्चित रूप से नियंत्रण प्रवाह हस्तांतरण पर अन्यथा-stmt को असाइन नहीं किया जाता है या अगर कोई और खंड नहीं है तो stmt के अंत बिंदु पर।
  • यदि वी के पास एक्सप्रप्रो के अंत में "निश्चित रूप से झूठी अभिव्यक्ति के बाद असाइन किया गया" है, तो यह निश्चित रूप से नियंत्रण प्रवाह हस्तांतरण पर अन्यथा-stmt पर असाइन किया गया है, और निश्चित रूप से नियंत्रण प्रवाह हस्तांतरण पर निश्चित रूप से असाइन नहीं किया गया है। यह निश्चित रूप से stmt के अंत बिंदु पर असाइन किया गया है अगर केवल तभी यह निश्चित रूप से तत्कालीन-बिंदु के अंत बिंदु पर असाइन किया गया हो।
  • अन्यथा, वी अगर कोई किसी और

शुरू में असाइन नहीं किए गए के लिए है निश्चित रूप से या तो तत्कालीन stmt वरना-stmt, या stmt के अंत बिंदु करने के लिए करने के लिए नियंत्रण प्रवाह हस्तांतरण पर नहीं सौंपा माना जाता है वैरिएबल को निश्चित रूप से निश्चित स्थान पर असाइन किया जाना माना जाता है, चर के लिए एक असाइनमेंट उस स्थान की ओर जाने वाले प्रत्येक संभावित निष्पादन पथ में होना चाहिए।

तकनीकी रूप से, निष्पादन पथ मौजूद है जहां if हालत झूठी है; यदि y को else में भी असाइन किया गया था, तो ठीक है, लेकिन ... विनिर्देश स्पष्ट रूप से if स्थिति को स्थानांतरित करने की कोई मांग नहीं करता है, यह स्थिति हमेशा सत्य होती है।

+0

असल में इस प्रश्न के spec का अधिक प्रासंगिक खंड है: * किसी भी अन्य कथन की शुरुआत में वी की निश्चित असाइनमेंट स्थिति निर्धारित है कि उस कथन की शुरुआत को लक्षित करने वाले सभी नियंत्रण प्रवाह हस्तांतरण पर निश्चित असाइनमेंट स्टेट v की जांच करके निर्धारित किया जाता है। ... संभावित नियंत्रण प्रवाह हस्तांतरण का सेट उसी तरह से निर्धारित किया जाता है जैसे कि कथन की पहुंच पहुंचने के लिए। * यदि स्थिति हमेशा सत्य होती है तो वाई का उपयोग केवल "अगर" के शरीर के माध्यम से किया जा सकता है, और उसके बाद शरीर, वाई निश्चित रूप से असाइन किया गया है। –

+0

@ स्पष्टीकरण के लिए एरिक चीयर्स –

+0

@Eric विनिर्देशों के विषय पर - यह ** ** महत्वपूर्ण या दबाने आदि नहीं है, लेकिन क्या आपके पास [वैकल्पिक पैरामीटर मुद्दे] के बारे में सोचने का समय है (http://stackoverflow.com/प्रश्न/8909811/सी तेज वैकल्पिक-पैरामीटर-ऑन-अधिरोहित-तरीकों/8912052 # 8912052)? –

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