यदि अशक्त बुरा है, तो आधुनिक भाषाएं इसे क्यों लागू करती हैं? [बन्द है]


82

मुझे यकीन है कि जावा या सी # जैसी भाषाओं के डिजाइनर अशक्त संदर्भों के अस्तित्व से जुड़े मुद्दों को जानते थे (देखें कि क्या अशक्त संदर्भ वास्तव में एक बुरी बात है? )। इसके अलावा एक विकल्प प्रकार को लागू करना वास्तव में अशक्त संदर्भों की तुलना में बहुत अधिक जटिल नहीं है।

उन्होंने इसे शामिल करने का फैसला क्यों किया? मुझे यकीन है कि अशक्त संदर्भों की कमी भाषा रचनाकारों और उपयोगकर्ताओं दोनों से बेहतर गुणवत्ता कोड (विशेष रूप से बेहतर पुस्तकालय डिजाइन) को प्रोत्साहित (या बल) करेगी।

क्या यह केवल रूढ़िवाद के कारण है - "अन्य भाषाओं में यह है, हमारे पास भी है ..."?


99
अशक्त महान है। मैं इसे प्यार करता हूं और हर दिन इसका इस्तेमाल करता हूं।
पीटर बी

17
@PieterB लेकिन क्या आप इसे अधिकांश संदर्भों के लिए उपयोग करते हैं, या क्या आप चाहते हैं कि अधिकांश संदर्भ शून्य न हों? तर्क यह नहीं है कि अशक्त डेटा नहीं होना चाहिए, केवल यह स्पष्ट और ऑप्ट-इन होना चाहिए।

11
@PieterB लेकिन जब बहुमत अशक्त नहीं होना चाहिए, क्या यह डिफ़ॉल्ट के बजाय अशक्त-क्षमता को अपवाद बनाने के लिए समझ में नहीं आएगा? ध्यान दें कि विकल्प प्रकारों की सामान्य डिजाइन अनुपस्थिति और अनपैकिंग के लिए स्पष्ट जाँच के लिए बाध्य करने के लिए है, किसी के पास जाने-माने जावा / सी # / भी हो सकते हैं ... ऑप्ट-इन नॉलेबल संदर्भों के लिए शब्दार्थ (जैसे कि अशक्त न हों, उपयोग करें) अगर शून्य)। यह कम से कम कुछ बग्स को रोकता है, और एक स्थैतिक विश्लेषण करता है जो लापता नल की जांच के बारे में अधिक व्यावहारिक शिकायत करता है।

20
डब्ल्यूटीएफ आप लोगों के साथ है? उन सभी चीजों में से, जो सॉफ्टवेयर के साथ गलत कर सकती हैं, एक अशांति को दूर करने की कोशिश करना कोई समस्या नहीं है। यह हमेशा एक ए वी / segfault उत्पन्न करता है और इसलिए तय हो जाता है। क्या बग की कमी इतनी है कि आपको इस बारे में चिंता करनी होगी? यदि ऐसा है, तो मेरे पास काफी अतिरिक्त है, और उनमें से कोई भी अशक्त संदर्भ / संकेत के साथ समस्याओं को आमंत्रित नहीं करता है।
मार्टिन जेम्स

13
@MartinJames "यह हमेशा एक एवी / सेगफॉल्ट उत्पन्न करता है और इसलिए ठीक हो जाता है" - नहीं, नहीं यह नहीं है।
detly

जवाबों:


97

डिस्क्लेमर: चूंकि मुझे व्यक्तिगत रूप से किसी भी भाषा के डिजाइनर का पता नहीं है, इसलिए मैं आपको जो भी उत्तर दूंगा वह सट्टा होगा।

खुद टोनी होरे से :

मैं इसे अपनी अरबों डॉलर की गलती कहता हूं। यह 1965 में अशक्त संदर्भ का आविष्कार था। उस समय, मैं ऑब्जेक्ट ओरिएंटेड भाषा (ALGOL W) में संदर्भ के लिए पहला व्यापक प्रकार का सिस्टम डिजाइन कर रहा था। मेरा लक्ष्य यह सुनिश्चित करना था कि संकलक द्वारा स्वचालित रूप से किए गए चेकिंग के साथ सभी संदर्भों का उपयोग पूरी तरह से सुरक्षित होना चाहिए। लेकिन मैं एक अशक्त संदर्भ में डालने के प्रलोभन का विरोध नहीं कर सकता था, केवल इसलिए कि इसे लागू करना इतना आसान था। इससे असंख्य त्रुटियां, कमजोरियां और सिस्टम क्रैश हो गए हैं, जिसने पिछले चालीस वर्षों में संभवतः एक अरब डॉलर का दर्द और क्षति पहुंचाई है।

जोर मेरा।

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

"हम सी ++ प्रोग्रामर के बाद थे। हम उनमें से बहुतों को लिस्प के आधे रास्ते तक खींचने में कामयाब रहे।" -Guy स्टील, जावा कल्पना के सह-लेखक

(स्रोत: http://www.paulgraham.com/icad.html )

और, बेशक, C ++ में शून्य है क्योंकि C के पास शून्य है, और C के ऐतिहासिक प्रभाव में जाने की कोई आवश्यकता नहीं है। C # एक प्रकार का अधिगृहीत J ++, जो Microsoft के जावा का कार्यान्वयन था, और यह Windows विकास के लिए पसंद की भाषा के रूप में C ++ को भी अधिगृहीत कर चुका है, इसलिए यह इसे किसी एक से प्राप्त कर सकता है।

EDIT यहाँ Hoare से एक और उद्धरण पर विचार करने लायक है:

समग्र रूप से प्रोग्रामिंग भाषाएं बहुत अधिक जटिल होती हैं, जिनका वे उपयोग करते थे: ऑब्जेक्ट ओरिएंटेशन, इनहेरिटेंस, और अन्य विशेषताओं को अभी भी एक सुसंगत और वैज्ञानिक रूप से अच्छी तरह से आधारित अनुशासन या शुद्धता के सिद्धांत के दृष्टिकोण से नहीं सोचा जा रहा है। । मेरा मूल अनुकरण, जिसे मैं एक वैज्ञानिक के रूप में जीवन भर अपना रहा हूं, वह यह है कि एक सभ्य प्रोग्रामिंग भाषा के डिजाइन पर धर्मान्तरण के साधन के रूप में शुद्धता के मापदंड का उपयोग किया जाता है - जो अपने उपयोगकर्ताओं और लोगों के लिए जाल सेट नहीं करता है कार्यक्रम के विभिन्न घटक इसके विनिर्देशन के विभिन्न घटकों से स्पष्ट रूप से मेल खाते हैं, इसलिए आप इसके बारे में महत्वपूर्ण रूप से तर्क कर सकते हैं। [...] संकलक सहित उपकरण, किसी सिद्धांत पर आधारित होते हैं, जिसका अर्थ है कि एक सही कार्यक्रम लिखना। फिलिप एल फ्रांका द्वारा -ऑरल इतिहास साक्षात्कार, 17 जुलाई 2002, कैम्ब्रिज, इंग्लैंड; चार्ल्स बैबेज संस्थान, मिनेसोटा विश्वविद्यालय। [ http://www.cbi.umn.edu/oh/display.phtml?id=343]

फिर से, मेरा जोर। Sun / Oracle और Microsoft कंपनियाँ हैं, और किसी भी कंपनी की निचली रेखा पैसा है। उन्हें होने वाले लाभ nullने विपक्ष को पछाड़ दिया है, या हो सकता है कि उन्होंने इस मुद्दे पर पूरी तरह से विचार करने के लिए बहुत समय सीमा तय की हो। एक अलग भाषा की गड़गड़ाहट के उदाहरण के रूप में जो संभवत: समय सीमा के कारण हुई:

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

(स्रोत: http://www.artima.com/intv/bloch13.html )


32
प्रिय downvoter: मैं अपने उत्तर को कैसे सुधार सकता हूं?
डोभाल

6
आपने वास्तव में इस सवाल का जवाब नहीं दिया; आपने केवल कुछ बाद के विचारों और कुछ अतिरिक्त हाथों के बारे में कुछ उद्धरण दिए हैं, जो "लागत" के बारे में हैं। (यदि शून्य एक अरब डॉलर की गलती है, तो एमएस और जावा द्वारा डॉलर को बचाया नहीं जाना चाहिए ताकि इसे लागू करके उस ऋण को कम किया जा सके?)
डग

29
@DougM आप मुझसे क्या करने की उम्मीद करते हैं, पिछले 50 वर्षों से हर भाषा डिजाइनर को मारा और उससे पूछा कि उसने nullअपनी भाषा में क्यों लागू किया? इस सवाल का कोई भी जवाब सट्टा नहीं होगा जब तक कि यह एक भाषा डिजाइनर से नहीं आता है। मुझे एरिक लिपर्ट के अलावा इस साइट के बारे में अक्सर कोई जानकारी नहीं है। अंतिम भाग कई कारणों से एक लाल हेरिंग है। एमएस और जावा के एपीआई के शीर्ष पर लिखे गए 3 पार्टी कोड की मात्रा जाहिर तौर पर एपीआई में कोड की मात्रा से अधिक है। इसलिए यदि आपके ग्राहक चाहते हैं null, तो आप उन्हें देते हैं null। आपको यह भी लगता है कि उन्होंने स्वीकार कर लिया nullहै कि उन्हें पैसा खर्च करना है
डोभाल

3
यदि एकमात्र उत्तर आप दे सकते हैं, तो सट्टा है, स्पष्ट रूप से अपने शुरुआती पैराग्राफ में बताएं। (आपने पूछा कि आप अपने उत्तर को कैसे बेहतर बना सकते हैं, और मैंने जवाब दिया। कोई भी अभिभाषक केवल टिप्पणी कर सकता है जिसे आप अनदेखा कर सकते हैं; यही कारण है कि लघुकोष्ठक अंग्रेजी में सभी के लिए हैं।)
डग्म

7
यह उत्तर उचित है; मैंने कुछ और विचार जोड़े हैं। मैं ध्यान देता हूं कि ICloneable.NET में समान रूप से टूटा हुआ है; दुर्भाग्य से यह एक ऐसी जगह है जहाँ जावा की कमियों को समय से नहीं सीखा गया था।
एरिक लिपर्ट

121

मुझे यकीन है कि जावा या सी # जैसी भाषाओं के डिजाइनर अशक्त संदर्भों के अस्तित्व से जुड़े मुद्दों को जानते थे

बेशक।

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

क्षमा करें मैं असहमत हूं! डिजाइन विचार जो C # 2 में अशक्त मूल्य प्रकारों में गए, वे जटिल, विवादास्पद और कठिन थे। उन्होंने दोनों भाषाओं और रनटाइम के कई महीनों के डिबेट, प्रोटोटाइप के कार्यान्वयन, और इसी तरह की डिजाइन टीमों को लिया और वास्तव में अशक्त मुक्केबाजी के शब्दार्थ को शिपिंग सी # 2.0 के बहुत करीब बदल दिया गया, जो बहुत विवादास्पद था।

उन्होंने इसे शामिल करने का फैसला क्यों किया?

सभी डिज़ाइन कई सूक्ष्म और स्थूल रूप से असंगत लक्ष्यों के बीच चयन करने की एक प्रक्रिया है; मैं केवल उन कारकों में से कुछ का संक्षिप्त विवरण दे सकता हूं जिन पर विचार किया जाएगा:

  • भाषा की विशेषताओं की रूढ़िवादिता को आमतौर पर एक अच्छी बात माना जाता है। C # में अशक्त मान प्रकार, गैर-अशक्त मान प्रकार और अशक्त संदर्भ प्रकार हैं। गैर-अशक्त संदर्भ प्रकार मौजूद नहीं है, जो टाइप सिस्टम को गैर-ऑर्थोगोनल बनाता है।

  • सी, सी ++ और जावा के मौजूदा उपयोगकर्ताओं के लिए परिचित होना महत्वपूर्ण है।

  • COM के साथ आसान अंतर महत्वपूर्ण है।

  • अन्य सभी .NET भाषाओं के साथ आसान अंतर महत्वपूर्ण है।

  • डेटाबेस के साथ आसान अंतर महत्वपूर्ण है।

  • शब्दार्थ की संगति महत्वपूर्ण है; अगर हमारे पास संदर्भ है TheKingOfFrance, null के बराबर है, जिसका हमेशा मतलब है कि "अभी फ्रांस का कोई राजा नहीं है", या इसका मतलब यह भी हो सकता है कि "निश्चित रूप से फ्रांस का एक राजा है? मुझे अभी नहीं पता कि यह अभी कौन है"? या इसका मतलब हो सकता है "फ्रांस में एक राजा होने की बहुत ही निरर्थक धारणा है, इसलिए सवाल भी नहीं पूछें?"। नल का मतलब इन सभी चीजों और C # में अधिक हो सकता है, और ये सभी अवधारणाएं उपयोगी हैं।

  • प्रदर्शन लागत महत्वपूर्ण है।

  • स्थैतिक विश्लेषण के लिए उत्तरदायी होना महत्वपूर्ण है।

  • प्रकार प्रणाली की स्थिरता महत्वपूर्ण है; हम कर सकते हैं हमेशा पता है कि गैर-व्यर्थ संदर्भ है कभी नहीं के तहत किसी भी अवैध माना गया परिस्थितियों? संदर्भ प्रकार के गैर-अशक्त क्षेत्र के साथ किसी वस्तु के निर्माता के बारे में क्या? ऐसे ऑब्जेक्ट के अंतिम रूप में क्या है, जहां ऑब्जेक्ट को अंतिम रूप दिया गया है क्योंकि संदर्भ में भरने वाला कोड एक अपवाद फेंक दिया था ? एक प्रकार की प्रणाली जो आपको इसकी गारंटी के बारे में बताती है, खतरनाक है।

  • और शब्दार्थ की संगति के बारे में क्या? उपयोग किए जाने पर अशक्त मूल्य प्रचारित होते हैं, लेकिन उपयोग किए जाने पर अशक्त संदर्भ अपवाद फेंक देते हैं। वह असंगत है; क्या यह असंगति कुछ लाभ के द्वारा उचित है?

  • क्या हम अन्य सुविधाओं को तोड़े बिना सुविधा को लागू कर सकते हैं? भविष्य की अन्य संभावित सुविधाएँ क्या सुविधा को रोकती हैं?

  • आप अपने पास मौजूद सेना के साथ युद्ध करने जाते हैं, न कि आप जो चाहते हैं। याद रखें, सी # 1.0 में जेनेरिक नहीं था, इसलिए Maybe<T>विकल्प के रूप में बात करना एक पूर्ण गैर-स्टार्टर है। क्या .NET को दो साल के लिए खिसक जाना चाहिए, जबकि रनटाइम टीम ने जेनरिक को जोड़ा, पूरी तरह से अशक्त संदर्भों को खत्म करने के लिए?

  • प्रकार प्रणाली की स्थिरता के बारे में क्या? आप Nullable<T>किसी भी मूल्य प्रकार के लिए कह सकते हैं - नहीं, रुको, यह एक झूठ है। आप नहीं कह सकते Nullable<Nullable<T>>। क्या आपको सक्षम होना चाहिए? यदि हां, तो इसके वांछित शब्दार्थ क्या हैं? क्या यह सार्थक है कि पूरे प्रकार की प्रणाली में इस विशेषता के लिए एक विशेष मामला है?

और इसी तरह। ये निर्णय जटिल हैं।


12
सब कुछ के लिए +1 लेकिन विशेष रूप से जेनेरिक को ऊपर लाना। यह भूलना आसान है कि जावा और सी # इतिहास दोनों में समय की अवधि थी जहां जेनरिक मौजूद नहीं था।
डोभाल

2
शायद एक गूंगा प्रश्न (मैं सिर्फ एक आईटी स्नातक हूं) - लेकिन विकल्प प्रकार को वाक्यविन्यास स्तर पर लागू नहीं किया जा सकता है (सीएलआर इसके बारे में कुछ भी नहीं जानता है) एक नियमित रूप से अशक्त संदर्भ के रूप में "उपयोग-मूल्य" की आवश्यकता होती है। कोड? मेरा मानना ​​है कि विकल्प प्रकारों को रनटाइम पर किसी भी चेक की आवश्यकता नहीं होती है।
21

2
@mrpyo: यकीन है, यह एक संभव कार्यान्वयन विकल्प है। अन्य डिजाइन विकल्पों में से कोई भी दूर नहीं जाता है, और उस कार्यान्वयन विकल्प के पास अपने स्वयं के कई पेशेवरों और विपक्ष हैं।
एरिक लिपर्ट

1
@mrpyo मुझे लगता है कि एक "हैश-वैल्यू" की जांच एक अच्छा विचार नहीं है। सैद्धांतिक रूप से यह एक बहुत अच्छा विचार है, लेकिन व्यवहार में, IMO यह सभी प्रकार के खाली चेक लाएगा, बस संकलक को संतुष्ट करने के लिए - जैसे कि जावा में चेक किए गए अपवाद और लोग इसे catchesकुछ भी नहीं करते हैं। मुझे लगता है कि संभवतः अवैध रूप से अमान्य स्थिति में संचालन जारी रखने के बजाय सिस्टम को उड़ाने देना बेहतर है।
NothingsImpossible

2
@voo: गैर-संदर्भ संदर्भ प्रकार की सारणियाँ बहुत सारे कारणों से कठिन हैं। कई संभावित समाधान हैं और उनमें से सभी विभिन्न कार्यों पर लागत लगाते हैं। सुपरकैट का सुझाव यह ट्रैक करना है कि क्या किसी तत्व को सौंपा जाने से पहले कानूनी रूप से पढ़ा जा सकता है, जो लागत लगाता है। आपका यह सुनिश्चित करना है कि सरणी दिखाई देने से पहले एक एलिमिनेटर प्रत्येक तत्व पर चलता है, जो लागत का एक अलग सेट लगाता है। तो यहाँ रगड़ना है: कोई फर्क नहीं पड़ता कि इन तकनीकों में से कोई भी चुनता है, कोई शिकायत करने जा रहा है कि यह उनके पालतू परिदृश्य के लिए कुशल नहीं है। यह सुविधा के खिलाफ गंभीर बिंदु है।
एरिक लिपर्ट

28

नल मूल्य की कमी का प्रतिनिधित्व करने का एक बहुत ही वैध उद्देश्य प्रदान करता है।

मैं कहूंगा कि मैं सबसे मुखर व्यक्ति हूं जो मुझे अशक्त और सभी सिरदर्द और पीड़ाओं के बारे में जानता है जो विशेष रूप से उदारवादी रूप से पैदा कर सकते हैं।

मेरा निजी रुख है कि लोग नल का उपयोग तभी कर सकते हैं जब वे इसे उचित और उचित ठहरा सकते हैं।

उदाहरणों को सही ठहराने वाला:

मृत्यु की तारीख आम तौर पर एक अशक्त क्षेत्र है। मृत्यु की तारीख के साथ तीन संभावित परिस्थितियां हैं। या तो व्यक्ति की मृत्यु हो गई है और तिथि ज्ञात है, व्यक्ति की मृत्यु हो गई है और तिथि अज्ञात है, या व्यक्ति मृत नहीं है और इसलिए मृत्यु की तारीख मौजूद नहीं है।

मृत्यु की तारीख भी एक डेटटाइम फ़ील्ड है और इसमें "अज्ञात" या "रिक्त" मान नहीं है। इसमें एक डिफ़ॉल्ट तिथि होती है जो आपके द्वारा उपयोग किए गए भाषा के आधार पर भिन्न होने पर एक नया डेटाटाइम बनाने पर आती है, लेकिन तकनीकी रूप से एक मौका है कि व्यक्ति वास्तव में उस समय मर जाता है और आपके "रिक्त मान" के रूप में फ़्लैग करेगा यदि आप थे डिफ़ॉल्ट दिनांक का उपयोग करें।

डेटा को ठीक से स्थिति का प्रतिनिधित्व करने की आवश्यकता होगी।

व्यक्ति की मृत्यु की अंतिम तिथि ज्ञात है (3/9/1984)

सरल, '3/9/1984'

व्यक्ति की मृत्यु की तारीख अज्ञात है

तो सबसे अच्छा क्या है? अशक्त , '0/0/0000', या '01 / 01/1869 '(या जो भी आपका डिफ़ॉल्ट मान है?)

व्यक्ति की मृत्यु की अंतिम तिथि लागू नहीं है

तो सबसे अच्छा क्या है? अशक्त , '0/0/0000', या '01 / 01/1869 '(या जो भी आपका डिफ़ॉल्ट मान है?)

तो चलो प्रत्येक मूल्य से अधिक लगता है ...

  • अशक्त , इसके निहितार्थ और सरोकार हैं, जिनसे आपको सावधान रहने की आवश्यकता है, अकस्मात इस बात की पुष्टि किए बिना इसमें हेरफेर करने की कोशिश की जा रही है कि यह पहले उदाहरण के लिए अशक्त नहीं है, लेकिन यह भी वास्तविक स्थिति का सबसे अच्छा प्रतिनिधित्व करता है ... यदि व्यक्ति मृत नहीं है मृत्यु की तारीख मौजूद नहीं है ... यह कुछ भी नहीं है ... यह शून्य है ...
  • 0/0/0000 , यह कुछ भाषाओं में ठीक हो सकता है, और यहां तक ​​कि बिना किसी तारीख के एक उचित प्रतिनिधित्व भी हो सकता है। दुर्भाग्य से कुछ भाषाएं और मान्यता इसे अमान्य डेटाटाइम के रूप में अस्वीकार कर देती हैं जो इसे कई मामलों में नहीं छोड़ता है।
  • 1/1/1869 (या जो भी आपका डिफ़ॉल्ट डेटाटाइम मान है) , यहाँ समस्या यह है कि इसे संभालना मुश्किल है। आप इसका उपयोग अपने मूल्य के अभाव के रूप में कर सकते हैं, सिवाय इसके कि क्या होगा अगर मैं अपने सभी रिकॉर्डों को फ़िल्टर करना चाहता हूं तो मेरे लिए मृत्यु की तारीख नहीं है? मैं उन लोगों को आसानी से फ़िल्टर कर सकता हूं जो वास्तव में उस तारीख को मर गए थे जो डेटा अखंडता मुद्दों का कारण बन सकते थे।

तथ्य यह है कभी कभी तुम है करो कुछ भी नहीं प्रतिनिधित्व करने के लिए और सुनिश्चित करें कि कभी कभी एक चर प्रकार है कि के लिए अच्छी तरह से काम है, लेकिन अक्सर वैरिएबल प्रकार कुछ भी नहीं प्रतिनिधित्व करने के लिए सक्षम होना चाहिए की जरूरत है।

अगर मेरे पास कोई सेब नहीं है तो मेरे पास 0 सेब हैं, लेकिन क्या होगा अगर मुझे नहीं पता कि मेरे पास कितने सेब हैं?

हर तरह से अशक्त दुर्व्यवहार और संभावित रूप से खतरनाक है, लेकिन कई बार यह आवश्यक है। यह कई मामलों में केवल डिफ़ॉल्ट है क्योंकि जब तक मैं एक मूल्य का अभाव प्रदान करता हूं और कुछ को इसका प्रतिनिधित्व करने की आवश्यकता होती है। (शून्य)


37
Null serves a very valid purpose of representing a lack of value.एक Optionया Maybeप्रकार प्रकार प्रणाली को दरकिनार किए बिना यह बहुत ही वैध उद्देश्य प्रदान करता है।
डोभाल

34
कोई भी यह तर्क नहीं दे रहा है कि मूल्य का कोई महत्व नहीं होना चाहिए, वे तर्क दे रहे हैं कि जो मूल्य गायब हो सकते हैं उन्हें स्पष्ट रूप से इस तरह चिह्नित किया जाना चाहिए , बजाय कि प्रत्येक मूल्य संभावित रूप से गायब हो।

2
मुझे लगता है कि RualStorge एसक्यूएल के संबंध में बात कर रहा था, क्योंकि ऐसे शिविर हैं जो हर स्तंभ को चिह्नित करते हैं NOT NULL। मेरा सवाल RDBMS से संबंधित नहीं था ...
mrpyo

5
"कोई मूल्य नहीं" और "अज्ञात मूल्य" के बीच अंतर करने के लिए +1
डेविड

2
क्या किसी व्यक्ति के राज्य को अलग करने के लिए यह अधिक समझ में नहीं आएगा? यानी एक Personप्रकार का एक प्रकार का stateक्षेत्र Stateहोता है, जो कि एक विभेदित संघ Aliveऔर है Dead(dateOfDeath : Date)
जॉन-हॉनसन

10

मैं इतनी दूर नहीं जाऊंगा जितना "अन्य भाषाओं में है, हमारे पास भी है ..." जैसे कि यह जोन्स के साथ रखने का कुछ प्रकार है। किसी भी नई भाषा की एक प्रमुख विशेषता अन्य भाषाओं में मौजूदा पुस्तकालयों के साथ हस्तक्षेप करने की क्षमता है (पढ़ें: सी)। चूंकि सी में अशक्त बिंदु होते हैं, इसलिए अंतर परत को आवश्यक रूप से नल की अवधारणा की आवश्यकता होती है (या कुछ अन्य "मौजूद नहीं है" समतुल्य है जब आप इसका उपयोग करते हैं)

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

लेकिन (विशेष रूप से जावा और सी # के लिए उनके परिचय और उनके लक्षित दर्शकों के समय के कारण) इस इंटरऑपरेबिलिटी परत के लिए विकल्प प्रकारों का उपयोग करने से संभवतः नुकसान होगा अगर उनके गोद लेने को टारपीडो नहीं किया गया। या तो विकल्प प्रकार को सभी तरह से पास किया जाता है, नरक को C ++ प्रोग्रामर के मध्य से 90 के दशक के अंत तक परेशान करता है - या इंटरऑपरेबिलिटी परत अपवादों को फेंक देती है जब nulls का सामना करना पड़ता है, तो नरक को C ++ प्रोग्रामर के मध्य से 90 के दशक के अंत तक परेशान करता है। ..


3
पहला पैराग्राफ मेरे लिए मायने नहीं रखता है। जावा में आपके द्वारा सुझाए गए आकार में C इंटरॉप नहीं है (जेएनआई है, लेकिन यह पहले से ही संदर्भों से संबंधित हर चीज के लिए एक दर्जन हुप्स के माध्यम से कूदता है ; प्लस यह शायद ही कभी अभ्यास में उपयोग किया जाता है), अन्य "आधुनिक" भाषाओं के लिए भी।

@delnan - क्षमा करें, मैं C # से अधिक परिचित हूं, जिसमें इस प्रकार का इंटरोप है। मैंने बल्कि यह मान लिया था कि कई संस्थापक जावा पुस्तकालय जेएनआई का उपयोग नीचे की ओर भी करते हैं।
तेलस्टिन

6
आप अशक्त होने की अनुमति देने के लिए एक अच्छा तर्क देते हैं, लेकिन आप फिर भी इसे प्रोत्साहित किए बिना अशक्त होने की अनुमति दे सकते हैं । स्काला इसका एक अच्छा उदाहरण है। यह मूल रूप से जावा एपिस के साथ इंटरॉपर्ट कर सकता है जो अशक्त का उपयोग करते हैं, लेकिन आपको इसे स्काला के भीतर उपयोग के लिए लपेटने के लिए प्रोत्साहित किया जाता है , जो कि उतना ही आसान है । व्यवहार में, लोगों को इसके लाभों को देखने में बहुत समय नहीं लगता है । Optionval x = Option(possiblyNullReference)Option
कार्ल बेवेलफेल्ट

1
विकल्प प्रकार हाथ से हाथ में (स्टैटिकली वेरिफाइड) पैटर्न से मेल खाते हैं, जो C # दुर्भाग्य से नहीं है। एफ # हालांकि करता है, और यह अद्भुत है।
स्टीवन एवर्स

1
@SteveEvers निजी निर्माणकर्ता, सीलबंद भीतरी वर्गों और एक Matchविधि जो प्रतिनिधियों को तर्क के रूप में लेती है , के साथ एक सार आधार वर्ग का उपयोग करके इसे नकली करना संभव है । फिर आप लैम्ब्डा एक्सप्रेशन पास करते हैं Match(नामांकित तर्कों का उपयोग करने के लिए बोनस अंक) और Matchसही कॉल करते हैं।
डोभाल

7

सबसे पहले, मुझे लगता है कि हम सभी सहमत हो सकते हैं कि अशक्तता की अवधारणा आवश्यक है। कुछ परिस्थितियाँ हैं जहाँ हमें जानकारी के अभाव का प्रतिनिधित्व करने की आवश्यकता है ।

nullसंदर्भ (और पॉइंटर्स) की अनुमति देना इस अवधारणा का केवल एक कार्यान्वयन है, और संभवतः सबसे लोकप्रिय है, हालांकि यह मुद्दों के लिए जाना जाता है: सी, जावा, पायथन, रूबी, पीएचपी, जावास्क्रिप्ट, ... सभी एक समान उपयोग करते हैं null

क्यों ? खैर, विकल्प क्या है?

कार्यात्मक भाषाओं जैसे हास्केल में आपके पास Optionया Maybeप्रकार है; हालांकि उन पर बनाया गया है:

  • पैरामीट्रिक प्रकार
  • बीजीय डेटा प्रकार

अब, क्या मूल C, Java, पायथन, रूबी या PHP उन विशेषताओं में से किसी का समर्थन करता है? नहीं जावा के त्रुटिपूर्ण जेनरिक भाषा के इतिहास में हाल ही में हैं और मैं किसी भी तरह दूसरों पर संदेह करता हूं यहां तक ​​कि उन्हें लागू भी करता हूं।

ये लो। nullआसान है, पैरामीट्रिक बीजगणितीय डेटा प्रकार कठिन हैं। लोग सबसे सरल विकल्प के लिए गए।


+1 के लिए "अशक्त आसान है, पैरामीट्रिक बीजीय डेटा प्रकार कठिन हैं।" लेकिन मुझे लगता है कि यह पैरामीट्रिक टाइपिंग और एडीटी के कठिन होने का मुद्दा नहीं था; यह सिर्फ इतना है कि वे आवश्यक नहीं हैं। यदि जावा को दूसरी ओर एक ऑब्जेक्ट सिस्टम के बिना भेज दिया गया था, तो यह फ्लॉप हो जाएगा; OOP एक "शोस्टॉपिंग" सुविधा थी, इसमें यदि आपके पास यह नहीं था, तो कोई भी दिलचस्पी नहीं रखता था।
डोभाल

@ डोवल: ठीक है, OOP जावा के लिए आवश्यक हो सकता है, लेकिन यह C :) के लिए नहीं था लेकिन यह सच है कि जावा का उद्देश्य सरल होना है। दुर्भाग्य से लोगों को लगता है कि एक सरल भाषा सरल कार्यक्रमों की ओर ले जाती है, जो थोड़े अजीब है (ब्रेनफक एक बहुत ही सरल भाषा है ...), लेकिन हम निश्चित रूप से सहमत हैं कि जटिल भाषा (C ++ ...) भले ही एक रामबाण नहीं है वे अविश्वसनीय रूप से उपयोगी हो सकते हैं।
मैथ्यू एम।

1
@ मैथ्यूएमएम .: रियल सिस्टम जटिल हैं। एक अच्छी तरह से डिज़ाइन की गई भाषा, जिसकी जटिलताएँ वास्तविक दुनिया प्रणाली से मेल खाती हैं, जटिल प्रणाली को सरल कोड के साथ मॉडलिंग करने की अनुमति दे सकती हैं। किसी भाषा की देखरेख करने का प्रयास बस उस प्रोग्रामर पर जटिलता को धक्का देता है जो इसका उपयोग कर रहा है।
सुपरकाट

@ सुपरकैट: मैं अधिक सहमत नहीं हो सका। या जैसा कि आइंस्टीन का विरोधाभास है: "सब कुछ जितना संभव हो उतना सरल बनाओ, लेकिन सरल नहीं।"
मैथ्यू एम।

@ मैथ्यूएमएम: आइंस्टीन कई मायनों में बुद्धिमान थे। ऐसी भाषाएं जो "सब कुछ एक वस्तु है, यह मानने की कोशिश करती है, जिसका संदर्भ Object" में संग्रहीत किया जा सकता है, यह पहचानने में विफल है कि व्यावहारिक अनुप्रयोगों को साझा किए जाने योग्य उत्परिवर्तनीय वस्तुओं की आवश्यकता होती है और अपरिवर्तनीय वस्तुओं (दोनों को मानों की तरह व्यवहार करना चाहिए) के साथ-साथ श्रावक और अपरिवर्तनीय हैं। संस्थाओं। Objectहर चीज के लिए एक ही प्रकार का उपयोग करना ऐसे भेदों की आवश्यकता को समाप्त नहीं करता है; यह केवल उन्हें सही ढंग से उपयोग करने के लिए कठिन बनाता है।
सुपरकैट

5

अशक्त / शून्य / कोई भी स्वयं दुष्ट नहीं है।

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

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

तो सवाल यह है कि, भाषा विकल्प लागू करने में विफल क्यों हैं? तथ्य की बात के रूप में, सभी समय C ++ की यकीनन सबसे लोकप्रिय भाषा में ऑब्जेक्ट चर को परिभाषित करने की क्षमता है जिसे असाइन नहीं किया जा सकता है NULL। यह टोनी होरे ने अपने भाषण में वर्णित "अशक्त समस्या" का समाधान है। अगली सबसे लोकप्रिय टाइप की गई भाषा, जावा में क्यों नहीं है? कोई यह पूछ सकता है कि इसमें सामान्य रूप से इतने दोष क्यों हैं , विशेष रूप से इसके प्रकार प्रणाली में। मुझे नहीं लगता कि आप वास्तव में कह सकते हैं कि भाषाएँ व्यवस्थित रूप से यह गलती करती हैं। कुछ करते हैं, कुछ नहीं करते।


1
एक कार्यान्वयन परिप्रेक्ष्य से जावा की सबसे बड़ी ताकत में से एक है, लेकिन एक भाषा के नजरिए से कमजोर है, यह है कि केवल एक गैर-आदिम प्रकार है: प्रमुख वस्तु संदर्भ। यह बहुत ही हल्के JVM कार्यान्वयन को संभव बनाते हुए, रनटाइम को सरल बनाता है। हालाँकि, इस डिज़ाइन का अर्थ है कि प्रत्येक प्रकार का एक डिफ़ॉल्ट मान होना चाहिए, और एक प्रमुख वस्तु संदर्भ के लिए एकमात्र संभव डिफ़ॉल्ट है null
सुपरकैट

खैर, किसी भी दर पर एक रूट गैर-आदिम प्रकार। भाषा के नजरिए से यह कमजोरी क्यों है? मुझे समझ में नहीं आता कि इस तथ्य की आवश्यकता क्यों है कि हर प्रकार का एक डिफ़ॉल्ट मान होता है (या इसके विपरीत कि क्यों कई रूट प्रकारों को डिफ़ॉल्ट मान नहीं होने देते हैं), और न ही क्यों यह एक कमजोरी है।
बीटी

गैर-आदिम किस तरह का क्षेत्र या सरणी तत्व पकड़ सकता है? कमजोरी यह है कि कुछ संदर्भों का उपयोग पहचान को एनकैप्सुलेट करने के लिए किया जाता है, और कुछ की पहचान की गई वस्तुओं के भीतर निहित मूल्यों को एनकैप्सुलेट करने के लिए किया जाता है। पहचान को अतिक्रमण करने के लिए उपयोग किए जाने वाले संदर्भ-प्रकार के चर के लिए, nullएकमात्र समझदार डिफ़ॉल्ट है। मूल्य को एन्कैप्सुलेट करने के लिए उपयोग किए जाने वाले संदर्भ, हालांकि, उन मामलों में एक समझदार डिफ़ॉल्ट व्यवहार हो सकता है जहां एक प्रकार का एक समझदार डिफ़ॉल्ट उदाहरण होगा या निर्माण कर सकता है। संदर्भों का व्यवहार कैसे करना चाहिए, इसके कई पहलू इस बात पर निर्भर करते हैं कि वे मान को कैसे और कैसे अलग करते हैं, लेकिन ...
सुपरकैट

... जावा प्रकार प्रणाली में व्यक्त करने का कोई तरीका नहीं है। तो fooएक के लिए केवल संदर्भ रखती int[]युक्त {1,2,3}और कोड चाहता है fooएक के लिए एक संदर्भ पकड़ करने के लिए int[]युक्त {2,2,3}, प्राप्त करने के लिए सबसे तेज़ तरीका है कि बढ़ाने के लिए किया जाएगा foo[0]। यदि कोड एक विधि को जानता है जो fooधारण करना चाहता है {1,2,3}, तो दूसरी विधि सरणी को संशोधित नहीं करेगी और न ही उस बिंदु से परे एक संदर्भ को बनाए रखेगी जहां fooइसे संशोधित करना चाहते हैं, इसे प्राप्त करने का सबसे तेज़ तरीका सरणी के संदर्भ को पास करना होगा। यदि जावा में "अल्पकालिक पढ़ा-केवल संदर्भ" प्रकार था, तो ...
सुपरकैट

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

4

क्योंकि प्रोग्रामिंग लैंग्वेज आम तौर पर तकनीकी रूप से सही होने के बजाय व्यावहारिक रूप से उपयोगी होती हैं। तथ्य यह है कि nullखराब या गायब डेटा या ऐसी स्थिति के कारण राज्य एक सामान्य घटना है जो अभी तक तय नहीं हुई है। तकनीकी रूप से बेहतर समाधान सभी अशक्त हैं बस अशक्त राज्यों की अनुमति देने और इस तथ्य को चूसने से कि प्रोग्रामर गलती करते हैं।

उदाहरण के लिए, यदि मैं एक सरल स्क्रिप्ट लिखना चाहता हूं जो फ़ाइल के साथ काम करती है, तो मैं छद्मकोड लिख सकता हूं जैसे:

file = openfile("joebloggs.txt")

for line in file
{
  print(line)
}

और यह बस विफल हो जाएगा अगर joebloggs.txt मौजूद नहीं है। बात यह है कि सरल लिपियों के लिए, जो शायद ठीक है और अधिक जटिल कोड में कई स्थितियों के लिए मुझे पता है कि यह मौजूद है और विफलता ऐसा नहीं होगा जिससे मुझे अपना समय बर्बाद करने के लिए मजबूर होना पड़े। सुरक्षित विकल्प मुझे संभावित विफलता की स्थिति से सही तरीके से निपटने के लिए मजबूर करके अपनी सुरक्षा प्राप्त करते हैं, लेकिन अक्सर मैं ऐसा नहीं करना चाहता, मैं बस प्राप्त करना चाहता हूं।


13
और यहाँ आपने एक उदाहरण दिया है कि नल के साथ क्या गलत है। उचित रूप से कार्यान्वित "ओपनफाइल" फ़ंक्शन को एक अपवाद (लापता फ़ाइल के लिए) फेंकना चाहिए जो सही निष्पादन के साथ वहीं हुआ, जो कि हुआ था। इसके बजाय अगर यह अशक्त हो जाता है तो यह आगे ( for line in file) को प्रचारित करता है और व्यर्थ अशक्त संदर्भ अपवाद को फेंकता है, जो इस तरह के एक सरल कार्यक्रम के लिए ठीक है, लेकिन अधिक जटिल प्रणालियों में वास्तविक डिबगिंग समस्याओं का कारण बनता है। यदि नल मौजूद नहीं थे, तो "ओपेनफाइल" का डिजाइनर इस गलती को करने में सक्षम नहीं होगा।
मप्र

2
+1 के लिए "क्योंकि प्रोग्रामिंग भाषा आम तौर पर तकनीकी रूप से सही होने के बजाय व्यावहारिक रूप से उपयोगी होने के लिए डिज़ाइन की गई है"
मार्टिन बा

2
हर प्रकार का विकल्प जो मुझे पता है कि आप एक ही छोटी अतिरिक्त विधि कॉल (रस्ट उदाहरण:) के साथ असफल-ऑन-नल करने की अनुमति देता है let file = something(...).unwrap()। अपने पीओवी पर निर्भर करते हुए, यह त्रुटियों को संभालने का एक आसान तरीका है या एक संक्षिप्त दावा है कि अशक्त नहीं हो सकता है। व्यर्थ समय कम से कम है, और आप अन्य स्थानों में समय बचाते हैं क्योंकि आपको यह पता लगाने की ज़रूरत नहीं है कि क्या कुछ अशक्त हो सकता है। एक अन्य लाभ (जो अतिरिक्त कॉल के लायक हो सकता है) यह है कि आप त्रुटि मामले को स्पष्ट रूप से अनदेखा करते हैं; जब यह विफल हो जाता है तो इसमें कोई संदेह नहीं है कि क्या गलत हुआ और कहां तय होने की जरूरत है।

4
@mrpyo सभी भाषाएँ अपवादों और / या अपवाद हैंडलिंग (a la try / catch) का समर्थन नहीं करती हैं। और अपवादों का दुरुपयोग भी किया जा सकता है - "प्रवाह नियंत्रण के रूप में अपवाद" एक सामान्य विरोधी पैटर्न है। यह परिदृश्य - एक फ़ाइल मौजूद नहीं है - AFAIK उस विरोधी पैटर्न का सबसे अक्सर उद्धृत उदाहरण है। ऐसा प्रतीत होता है कि आप एक बुरे अभ्यास को दूसरे के साथ बदल रहे हैं।
डेविड

8
@mrpyo if file exists { open file }एक दौड़ की स्थिति से ग्रस्त है। यह जानने का एकमात्र विश्वसनीय तरीका है कि कोई फ़ाइल खोलने में सफल होगी या नहीं इसे खोलने का प्रयास करें।

4

NULL( nil, या Nil, या null, Nothingया जो भी इसे आपकी पसंदीदा भाषा में कहा जाता है) के स्पष्ट, व्यावहारिक उपयोग हैं ।

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

char *buf = malloc(20);
if (!buf)
{
    perror("memory allocation failed");
    exit(1);
}

यहाँ NULLसे लौटा malloc(3)एक विफलता के मार्कर के रूप में प्रयोग किया जाता है।

जब विधि / फ़ंक्शन तर्क में उपयोग किया जाता है, तो यह तर्क के लिए डिफ़ॉल्ट उपयोग का संकेत दे सकता है या आउटपुट तर्क को अनदेखा कर सकता है। नीचे उदाहरण है।

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

NSError *err = nil;
NSString *content = [NSString stringWithContentsOfURL:sourceFile
                                         usedEncoding:NULL // This output is ignored
                                                error:&err];
if (!content) // If the object is null, we have a soft error to recover from
{
    fprintf(stderr, "error: %s\n", [[err localizedDescription] UTF8String]);
    if (!error) // Check if the parent method ignored the error argument
        *error = err;
    return nil; // Go back to parent layer, with another soft error.
}

यहां, सॉफ्ट एरर प्रोग्राम को न पकड़े जाने पर क्रैश होने का कारण नहीं बनता है। यह जावा की तरह क्रेजी ट्राइ-कैच को समाप्त करता है और प्रोग्राम फ्लो में बेहतर नियंत्रण रखता है क्योंकि सॉफ्ट एरर में रुकावट नहीं आती है (और कुछ शेष हार्ड अपवाद आमतौर पर रिकवर नहीं होते हैं और अनकैप्ड नहीं होते हैं)


5
समस्या यह है कि चर को अलग करने का कोई तरीका नहीं है जो कभी भी nullउन लोगों से नहीं होना चाहिए जो कि होना चाहिए। उदाहरण के लिए, यदि मैं एक नया प्रकार चाहता हूं जिसमें जावा में 5 मान शामिल हैं, तो मैं एक एनम का उपयोग कर सकता हूं, लेकिन मुझे जो मिलता है वह 6 मान (5 मैं चाहता था + null) धारण कर सकता है । यह प्रकार प्रणाली में एक दोष है।
डोभाल

@ डोवाल यदि ऐसी स्थिति है तो बस NULL को एक अर्थ प्रदान करें (या यदि आपके पास कोई डिफ़ॉल्ट है, तो इसे डिफ़ॉल्ट मान के समानार्थी के रूप में मानें) या NULL का उपयोग करें (जो कभी भी पहली जगह में प्रकट नहीं होना चाहिए) नरम त्रुटि के मार्कर के रूप में। (यानी त्रुटि लेकिन कम से कम अभी तक दुर्घटनाग्रस्त नहीं हुई)
मैक्सथन चान

1
@MaxtonChan Nullको केवल एक अर्थ दिया जा सकता है जब एक प्रकार का मान कोई डेटा नहीं ले जाता है (उदाहरण के लिए मान)। जैसे ही आपके मूल्य कुछ और अधिक जटिल होते हैं (जैसे एक संरचना), nullको उस प्रकार के लिए अर्थ देने वाले अर्थ को असाइन नहीं किया जा सकता है। nullएक संरचना या एक सूची के रूप में उपयोग करने का कोई तरीका नहीं है । और, फिर से, nullएक त्रुटि संकेत के रूप में उपयोग करने के साथ समस्या यह है कि हम यह नहीं बता सकते कि क्या अशक्त वापस आ सकता है या अशक्त स्वीकार कर सकता है। आपके कार्यक्रम में कोई भी वैरिएबल nullतब तक हो सकता है जब तक कि आप nullहर एक उपयोग से पहले हर एक की जांच करने के लिए अत्यंत सावधानीपूर्वक न हों , जो कोई भी नहीं करता है।
डोभाल

1
@ डोवाल: अपरिवर्तनीय संदर्भ प्रकार के संबंध nullमें एक प्रयोग करने योग्य डिफ़ॉल्ट मूल्य (जैसे कि stringखाली स्ट्रिंग के रूप में व्यवहार करने का डिफ़ॉल्ट मान है , पूर्ववर्ती कॉमन ऑब्जेक्ट मॉडल के तहत किया था) होने में कोई विशेष अंतर्निहित कठिनाई नहीं होगी । सभी कि आवश्यक हो गया होता भाषाओं का उपयोग करने के लिए हो गया होता callकरने के बजाय callvirtजब गैर आभासी सदस्यों लागू।
सुपरकैट

@supercat यह एक अच्छा बिंदु है, लेकिन अब आपको अपरिवर्तनीय और गैर-अपरिवर्तनीय प्रकारों के बीच अंतर करने के लिए समर्थन जोड़ने की आवश्यकता नहीं है? मुझे यकीन नहीं है कि एक भाषा में जोड़ना कितना तुच्छ है।
डोभाल

4

दो संबंधित हैं, लेकिन थोड़ा अलग मुद्दे हैं:

  1. nullसभी में मौजूद होना चाहिए ? या क्या आपको हमेशा उपयोग करना चाहिए Maybe<T>जहां नल उपयोगी है?
  2. क्या सभी संदर्भ अशक्त होने चाहिए? यदि नहीं, तो कौन सा डिफ़ॉल्ट होना चाहिए?

    स्पष्ट रूप से अशोभनीय संदर्भ प्रकारों को घोषित करने के string?समान या nullहोने से प्रोग्रामर के लिए उपयोग किए जाने वाले से बहुत अलग होने के बिना समस्याओं के कारणों के अधिकांश (लेकिन सभी नहीं) से बचना होगा ।

मैं कम से कम आपके साथ सहमत हूं कि सभी संदर्भों को अशक्त नहीं होना चाहिए। लेकिन अशक्तता से बचना उसकी जटिलताओं के बिना नहीं है:

.NET उन सभी फ़ील्ड्स को इनिशियलाइज़ करता है, default<T>जिन्हें पहले प्रबंधित कोड द्वारा एक्सेस किया जा सकता है। इसका मतलब यह है कि संदर्भ प्रकारों के लिए आपको आवश्यकता है nullया कुछ समान है और मूल्य प्रकारों को बिना किसी कोड के शून्य के कुछ प्रकार से आरंभ किया जा सकता है । हालांकि इन दोनों में भारी गिरावट है, आरंभिकता की सादगी ने defaultउन डाउनसाइड्स को पछाड़ दिया है।

  • उदाहरण के लिए, आप thisपॉइंटर को प्रबंधित कोड में उजागर करने से पहले फ़ील्ड को आरंभीकृत करने के द्वारा इसके चारों ओर काम कर सकते हैं । सी # के साथ तुलना में, चेंजर ने कंस्ट्रक्टर चेनिंग से अलग सिंटैक्स का उपयोग करते हुए इस मार्ग को पार कर लिया।

  • के लिए स्थिर क्षेत्रों जब तक आप के बाद से आप बस नहीं छुपा सकते कोड किस तरह का एक क्षेत्र प्रारंभकर्ता में चला सकते हैं पर मजबूत प्रतिबंध मुद्रा इस सुनिश्चित करने, कठिन है thisसूचक।

  • संदर्भ प्रकारों के सरणियों को कैसे प्रारंभ करें? एक विचार करें List<T>जो एक सरणी द्वारा समर्थित है जिसकी लंबाई की तुलना में बड़ी क्षमता है। शेष तत्वों का कुछ मूल्य होना आवश्यक है।

एक और समस्या यह है कि यह उन तरीकों की अनुमति नहीं देता है जैसे कि वे bool TryGetValue<T>(key, out T value)लौटते हैं default(T)जैसे valueकि उन्हें कुछ भी नहीं मिलता है। हालांकि इस मामले में यह तर्क देना आसान है कि आउट पैरामीटर पहले स्थान पर खराब डिज़ाइन है और इस विधि को एक भेदभावपूर्ण संघ या इसके बजाय शायद वापस लौटना चाहिए ।

इन सभी समस्याओं को हल किया जा सकता है, लेकिन यह "अशक्त और सब ठीक है" जितना आसान नहीं है।


List<T>IMHO सबसे अच्छा उदाहरण है, क्योंकि यह आवश्यकता होगी या तो हर कि Tउनका डिफ़ॉल्ट मान, कि समर्थन की दुकान में हर आइटम एक होना Maybe<T>एक अतिरिक्त "अगर है" क्षेत्र के साथ, तब भी जब Tएक है Maybe<U>, या के लिए कोड है कि List<T>व्यवहार अलग तरह से निर्भर करता है चाहे पर Tअपने आप में एक नल प्रकार है। मैं का प्रारंभ करने पर विचार करेंगे T[]एक डिफ़ॉल्ट मान पर तत्व उन विकल्पों के कम से कम बुराई होने के लिए है, लेकिन यह निश्चित रूप से इसका मतलब है कि तत्वों की जरूरत है एक डिफ़ॉल्ट मान।
सुपरकैट

जंग 1 बिंदु का अनुसरण करती है - कोई अशक्त नहीं। सीलोन बिंदु 2 का अनुसरण करता है - डिफ़ॉल्ट रूप से गैर-शून्य। जो संदर्भ शून्य हो सकते हैं, उन्हें स्पष्ट रूप से एक संघ प्रकार के साथ घोषित किया जाता है जिसमें एक संदर्भ या अशक्त शामिल होता है, लेकिन अशक्त कभी भी एक सादे संदर्भ का मूल्य नहीं हो सकता है। परिणामस्वरूप, भाषा पूरी तरह से सुरक्षित है और कोई NullPointerException नहीं है क्योंकि यह शब्दार्थ संभव नहीं है।
जिम बाल्टर

2

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

अलग-अलग भाषा और सिस्टम अलग-अलग तरीके अपनाते हैं।

  • एक दृष्टिकोण यह कहना होगा कि जो कुछ नहीं लिखा गया है उसे पढ़ने का कोई भी प्रयास तत्काल त्रुटि को ट्रिगर करेगा।

  • एक दूसरा दृष्टिकोण यह है कि कोड को हर स्थान पर कुछ मूल्य की आपूर्ति करने के लिए कोड की आवश्यकता होती है, इससे पहले कि इसे पढ़ना संभव हो, भले ही संग्रहित मूल्य के लिए कोई अर्थ उपयोगी हो।

  • एक तीसरा तरीका यह है कि केवल समस्या को अनदेखा करें और जो कुछ भी "स्वाभाविक रूप से" होगा उसे होने दें।

  • एक चौथा दृष्टिकोण यह कहना है कि हर प्रकार का एक डिफ़ॉल्ट मान होना चाहिए, और कोई भी स्लॉट जो किसी अन्य चीज के साथ नहीं लिखा गया है, उस मान के लिए डिफ़ॉल्ट होगा।

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

शब्दार्थ, यदि किसी के पास एक प्रकार customersकी सरणी है Customer[20], और एक प्रयास के Customer[4].GiveMoney(23)बिना कुछ भी संग्रहीत किया जाता है Customer[4], तो निष्पादन को फंसाना होगा। कोई यह तर्क दे सकता है कि Customer[4]कोड को प्रयास करने तक प्रतीक्षा करने के बजाय, पढ़ने का प्रयास तुरंत फंस जाना चाहिए GiveMoney, लेकिन ऐसे बहुत से मामले हैं जहां यह एक स्लॉट को पढ़ने के लिए उपयोगी है, यह पता करें कि यह एक मूल्य नहीं रखता है, और फिर उसका उपयोग करें जानकारी, कि पढ़ने का प्रयास विफल होने के कारण अक्सर एक बड़ा उपद्रव होगा।

कुछ भाषाओं में एक को यह निर्दिष्ट करने की अनुमति मिलती है कि कुछ चर में शून्य कभी नहीं होना चाहिए, और नल को संचय करने के किसी भी प्रयास को तत्काल जाल को ट्रिगर करना चाहिए। यह एक उपयोगी विशेषता है। सामान्य तौर पर, हालांकि, कोई भी भाषा जो प्रोग्रामर को संदर्भों के सरणियों को बनाने की अनुमति देती है, उन्हें या तो रिक्त सरणी तत्वों की संभावना के लिए अनुमति देनी होगी, या फिर सरणी तत्वों के आरंभिक डेटा के लिए मजबूर करना होगा जो संभवतः सार्थक नहीं हो सकते।


एक नहीं होता Maybe/ Optionप्रकार # 2 के साथ समस्या का समाधान है, क्योंकि अगर आप अपने संदर्भ के लिए एक मूल्य की जरूरत नहीं है अभी तक लेकिन होगा भविष्य में एक, तो आप सिर्फ स्टोर कर सकते हैं Nothingएक में Maybe <Ref type>?
डोभाल

@ डोभाल: नहीं, यह समस्या को हल नहीं करेगा - कम से कम, फिर से अशक्त संदर्भों को पेश किए बिना नहीं। क्या "नथिंग" टाइप के सदस्य की तरह काम करना चाहिए? यदि हां, तो कौन सा? या इसे एक अपवाद फेंक देना चाहिए? किस मामले में, आप कैसे nullसही / समझदारी से उपयोग करने से बेहतर हैं ?
cHao

@ डोभाल: बैकिंग का प्रकार List<T>होना चाहिए a T[]या a Maybe<T>? समर्थन प्रकार के बारे में क्या List<Maybe<T>>?
सुपरकैट

@supercat मुझे यकीन नहीं है कि एक एकल मूल्य Maybeरखने के Listबाद से एक समर्थन प्रकार कैसे समझ में आता है Maybe। क्या आपका मतलब था Maybe<T>[]?
डोभाल

@cHao Nothingकेवल प्रकार के मूल्यों को सौंपा जा सकता है Maybe, इसलिए यह असाइन करना पसंद नहीं है nullMaybe<T>और Tदो अलग-अलग प्रकार हैं।
डोभाल
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.