यह प्रश्न २० सितंबर २०१० को मेरे ब्लॉग का विषय था । जोश और चाड के जवाब ("वे कोई मूल्य नहीं जोड़ते हैं, इसलिए उनकी आवश्यकता क्यों है?" और "अतिरेक को खत्म करने के लिए") मूल रूप से सही हैं। मांस को थोड़ा और अधिक:
ऑब्जेक्ट इनिशियलाइज़र्स की "बड़ी विशेषता" के भाग के रूप में आपको तर्क सूची को खत्म करने की अनुमति देने की सुविधा "शर्करा" सुविधाओं के लिए हमारे बार से मिली। कुछ बिंदुओं पर हमने विचार किया:
- डिजाइन और विनिर्देश लागत कम थी
- हम बड़े पैमाने पर पार्सर कोड को बदलने जा रहे थे जो वैसे भी ऑब्जेक्ट निर्माण को संभालता है; बड़ी सूची की लागत की तुलना में पैरामीटर सूची को वैकल्पिक बनाने की अतिरिक्त विकास लागत बड़ी नहीं थी
- बड़ी सुविधा की लागत की तुलना में परीक्षण का बोझ अपेक्षाकृत छोटा था
- प्रलेखन बोझ अपेक्षाकृत छोटा था ...
- रखरखाव का बोझ छोटा होने का अनुमान था; मुझे इस सुविधा में रिपोर्ट किए गए वर्षों के बाद से कोई भी बग याद नहीं है।
- इस क्षेत्र में भविष्य की सुविधाओं के लिए कोई भी तुरंत स्पष्ट जोखिम नहीं है। (आखिरी चीज जो हम करना चाहते हैं वह अब एक सस्ता, आसान फीचर है जो भविष्य में एक अधिक सम्मोहक सुविधा को लागू करने के लिए बहुत कठिन बनाता है।)
- यह सुविधा भाषा के शाब्दिक, व्याकरणिक या अर्थ विश्लेषण के लिए कोई नई अस्पष्टता नहीं जोड़ती है। यह "आंशिक कार्यक्रम" विश्लेषण के प्रकार के लिए कोई समस्या नहीं है जो IDE के "IntelliSense" इंजन द्वारा टाइप किए जाने के दौरान किया जाता है। और इसी तरह।
- सुविधा बड़ी वस्तु इनिशियलाइज़ेशन फ़ीचर के लिए एक सामान्य "स्वीट स्पॉट" को हिट करती है; आम तौर पर यदि आप किसी ऑब्जेक्ट इनिलाइज़र का उपयोग कर रहे हैं तो यह ठीक है क्योंकि ऑब्जेक्ट का निर्माता आपको आपके इच्छित गुणों को सेट करने की अनुमति नहीं देता है। ऐसी वस्तुओं के लिए बस "प्रॉपर्टी बैग" होना बहुत ही आम बात है, जो पहले स्थान पर ctor में कोई पैरामीटर नहीं है।
तब आपने ऑब्जेक्ट निर्माण अभिव्यक्ति के डिफ़ॉल्ट कंस्ट्रक्टर कॉल में खाली कोष्ठक को वैकल्पिक क्यों नहीं बनाया , जिसमें ऑब्जेक्ट इनिशियलाइज़र नहीं है?
उपरोक्त मानदंडों की उस सूची पर एक और नज़र डालें। उनमें से एक यह है कि परिवर्तन एक कार्यक्रम के शाब्दिक, व्याकरणिक या अर्थ विश्लेषण में किसी भी नई अस्पष्टता का परिचय नहीं देता है। आपका प्रस्तावित परिवर्तन करता है एक अर्थगत विश्लेषण अस्पष्टता परिचय:
class P
{
class B
{
public class M { }
}
class C : B
{
new public void M(){}
}
static void Main()
{
new C().M(); // 1
new C.M(); // 2
}
}
पंक्ति 1 एक नया C बनाता है, डिफ़ॉल्ट कंस्ट्रक्टर को कॉल करता है, और फिर नई ऑब्जेक्ट पर इंस्टेंस विधि M को कॉल करता है। लाइन 2 बीएम का एक नया उदाहरण बनाता है और अपने डिफ़ॉल्ट निर्माता को कॉल करता है। यदि पंक्ति 1 पर कोष्ठक वैकल्पिक थे तो पंक्ति 2 अस्पष्ट होगी। फिर हमें अस्पष्टता को हल करने वाले नियम के साथ आना होगा; हम इसे एक त्रुटि नहीं बना सकते क्योंकि यह एक ब्रेकिंग परिवर्तन होगा जो मौजूदा कानूनी C # प्रोग्राम को एक टूटे हुए प्रोग्राम में बदलता है।
इसलिए नियम को बहुत जटिल बनाना होगा: अनिवार्य रूप से कि कोष्ठक केवल उन मामलों में वैकल्पिक हैं जहां वे अस्पष्टता का परिचय नहीं देते हैं। हमें उन सभी संभावित मामलों का विश्लेषण करना होगा जो अस्पष्टता का परिचय देते हैं और फिर उनका पता लगाने के लिए संकलक में कोड लिखते हैं।
उस प्रकाश में, वापस जाएं और मेरे द्वारा उल्लिखित सभी लागतों को देखें। उनमें से कितने अब बड़े हो गए हैं? जटिल नियमों में बड़े डिजाइन, कल्पना, विकास, परीक्षण और प्रलेखन लागत हैं। भविष्य में सुविधाओं के साथ अनपेक्षित बातचीत के साथ जटिल नियम समस्याओं का कारण बन सकते हैं।
सभी के लिए क्या? एक छोटा ग्राहक लाभ, जो भाषा में कोई नई प्रतिनिधित्वात्मक शक्ति नहीं जोड़ता है, लेकिन पागल कोने के मामलों को जोड़ देता है, जो "ग़ाचा" की प्रतीक्षा कर रहे हैं, जो कुछ गरीब असंतुष्ट आत्मा पर चलता है। इस तरह की सुविधाएँ तुरंत कट जाती हैं और "कभी नहीं करें" सूची में डाल दी जाती हैं।
आपने उस विशेष अस्पष्टता का निर्धारण कैसे किया?
वह एक तुरंत स्पष्ट था; जब एक बिंदीदार नाम की उम्मीद की जाती है, तो यह निर्धारित करने के लिए मैं सी # में नियमों से बहुत परिचित हूं।
एक नई सुविधा पर विचार करते समय आप कैसे निर्धारित करते हैं कि यह किसी भी अस्पष्टता का कारण बनता है? हाथ से, औपचारिक प्रमाण से, मशीन विश्लेषण से, क्या?
सभी तीन। ज्यादातर हम सिर्फ कल्पना और उस पर नूडल देखते हैं, जैसा कि मैंने ऊपर किया था। उदाहरण के लिए, मान लें कि हम एक नए उपसर्ग ऑपरेटर को C # में जोड़ना चाहते थे जिसे "फ्रोब" कहा जाता है:
x = frob 123 + 456;
(अद्यतन: frob
निश्चित रूप से await
, यहाँ विश्लेषण अनिवार्य रूप से विश्लेषण है कि डिजाइन टीम को जोड़ते समय हुआ था await
।)
"फ्रोब" यहां "नया" या "++" जैसा है - यह किसी प्रकार की अभिव्यक्ति से पहले आता है। हम वांछित वरीयता और सहानुभूति और इतने पर काम करेंगे, और फिर सवाल पूछना शुरू कर देंगे "क्या होगा यदि कार्यक्रम में पहले से ही एक प्रकार, क्षेत्र, संपत्ति, घटना, विधि, निरंतर, या स्थानीय कहा जाता है?" यह तुरंत मामलों की ओर ले जाएगा जैसे:
frob x = 10;
क्या इसका मतलब यह है कि "x = 10 के परिणाम पर फ्रोब ऑपरेशन करें, या x नामक प्रकार के फ्रोब का एक वैरिएबल बनाएं और उसमें 10 को असाइन करें?" (या, अगर फ्रोबिंग एक चर का उत्पादन करता है, तो यह 10 से एक असाइनमेंट हो सकता है frob x
। सब के बाद, *x = 10;
पर्स और कानूनी है अगर x
है int*
।)
G(frob + x)
इसका मतलब है कि "एक्स पर यूनिरी प्लस ऑपरेटर का परिणाम" या "एक्सप्रेशन फ़्राब को एक्स" में जोड़ें?
और इसी तरह। इन अस्पष्टताओं को हल करने के लिए हम उत्तराधिकार का परिचय दे सकते हैं। जब आप कहते हैं "var x = 10;" वह अस्पष्ट है; इसका अर्थ "एक्स के प्रकार का अनुमान लगाना" हो सकता है या इसका मतलब "एक्स प्रकार का है" हो सकता है। इसलिए हमारे पास एक अनुमान है: हम पहले एक प्रकार का नाम देखने का प्रयास करते हैं, और केवल अगर कोई मौजूद नहीं है तो हम एक्स के प्रकार का अनुमान लगाते हैं।
या, हम वाक्यविन्यास को बदल सकते हैं ताकि यह अस्पष्ट न हो। जब उन्होंने C # 2.0 डिज़ाइन किया तो उन्हें यह समस्या हुई:
yield(x);
क्या इसका मतलब है "पैदावार x को एक पुनरावृत्त में" या "तर्क एक्स के साथ उपज विधि को बुलाओ?" इसे बदलकर
yield return(x);
यह अब असंदिग्ध है।
एक वस्तु इनिशियलाइज़र में वैकल्पिक पेरेन्स के मामले में यह इस कारण से सीधा है कि वहाँ अस्पष्टताएं शुरू की गई हैं या नहीं क्योंकि स्थितियों की संख्या जिसमें कुछ के साथ शुरू करने की अनुमति है, जो {के साथ शुरू होती है, वह बहुत छोटी है । मूल रूप से सिर्फ विभिन्न स्टेटमेंट संदर्भ, स्टेटमेंट लैम्ब्डा, ऐरन इनिशियलाइज़र और इसके बारे में है। सभी मामलों के माध्यम से तर्क करना और यह दिखाना आसान है कि कोई अस्पष्टता नहीं है। यह सुनिश्चित करना कि IDE का कुशल होना कुछ कठिन है, लेकिन बहुत अधिक परेशानी के बिना भी किया जा सकता है।
इस तरह की कल्पना के साथ चारों ओर चक्कर लगाना पर्याप्त है। यदि यह एक विशेष रूप से मुश्किल विशेषता है तो हम भारी उपकरण खींचते हैं। उदाहरण के लिए, जब LINQ, कंपाइलर दोस्तों में से एक और IDE लोगों में से एक है, जो दोनों के पास पार्सर सिद्धांत में एक पृष्ठभूमि है, तो उन्होंने खुद को एक पार्सर जनरेटर बनाया है जो अस्पष्टता की तलाश में व्याकरण का विश्लेषण कर सकता है, और फिर क्वेरी कॉम्प्रिहेंशन के लिए प्रस्तावित सी # ग्रामर को इसमें फीड किया जा सकता है। ; ऐसा करने से कई मामले सामने आए, जहां सवाल अस्पष्ट थे।
या, जब हमने C # 3.0 में लैम्ब्डा पर उन्नत प्रकार की आक्षेप किया, तो हमने अपने प्रस्ताव लिखे और फिर उन्हें कैम्ब्रिज में माइक्रोसॉफ्ट रिसर्च के तालाब पर भेज दिया, जहाँ भाषाओं की टीम ने एक औपचारिक प्रमाण तैयार करने के लिए काफी अच्छा था कि प्रकार का प्रस्ताव। सैद्धांतिक रूप से ध्वनि।
क्या आज C # में अस्पष्टताएँ हैं?
ज़रूर।
G(F<A, B>(0))
C # 1 में यह स्पष्ट है कि इसका क्या मतलब है। यह समान है:
G( (F<A), (B>0) )
यही है, यह जी को दो तर्कों के साथ बुलाता है जो बूल हैं। C # 2 में, इसका मतलब यह हो सकता है कि C # 1 में इसका क्या अर्थ है, लेकिन इसका मतलब यह भी हो सकता है "सामान्य विधि F के पास 0 जो टाइप पैरामीटर A और B लेता है, और फिर F से G के परिणाम को पास करें"। हमने पार्सर में एक जटिल हेयूरिस्टिक जोड़ा, जो यह निर्धारित करता है कि आप में से दो मामलों का क्या मतलब है।
इसी तरह, C # 1.0 में भी कलाकार अस्पष्ट हैं:
G((T)-x)
क्या वह "कास्ट-एक्स टू टी" या "टी से एक्सट्रैक्ट एक्स" है? फिर, हमारे पास एक अनुमान है जो एक अच्छा अनुमान लगाता है।