2009-03-13 11 views
7

मैं लोगों को इस बात की बात सुनता रहता हूं कि गैर-निरर्थक संदर्भ प्रकार कितने बग हल करेंगे और प्रोग्रामिंग को इतना आसान बना देंगे। यहां तक ​​कि नल के निर्माता भी इसे billion dollar mistake कहते हैं, और Spec# ने इस समस्या का मुकाबला करने के लिए गैर-शून्य प्रकारों को पेश किया है।गैर-नामुमकिन प्रकारों के बारे में बहस

संपादित करें: SpeC# के बारे में मेरी टिप्पणी को अनदेखा करें। मैंने गलत समझा कि यह कैसे काम करता है।

संपादित करें 2: मैं गलत लोगों से बात कर रही किया जाना चाहिए, मैं वास्तव में, किसी :-)


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

class Class { ... } 

void main() { 
    Class c = nullptr; 
    // ... ... ... code ... 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

BAM! उपयोग का उल्लंघन। कोई c प्रारंभ करना भूल गया।


अब इस पर विचार करें:

class Class { ... } 

void main() { 
    Class c = new Class(); // set to new Class() by default 
    // ... ... ... code ... 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

ओह। लूप चुपचाप छोड़ दिया जाता है। समस्या को ट्रैक करने में कुछ समय लग सकता है।


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

+0

दूसरों को नल का आनंद लेने के लिए अच्छा लगता है, मैं अभी भी स्कूल में हूं इसलिए मुझे लगता है कि कुछ ऐसा है जो मुझे याद आ रहा है। –

+1

"कोई मूल्य नहीं" संभालने के अधिक सिद्धांतबद्ध तरीके हैं। एनयूएलएल में प्राचीन प्रकार, जैसे int। एक प्रकार के सिस्टम के लिए केवल सभी प्रकार के मूल्यों की निरंतरता का प्रतिनिधित्व करने के लिए बेहतर है, बजाय संदर्भों के लिए केवल स्पष्ट रूप से। हास्केल के "हो सकता है" और एमएल/ओकैमल/एफ # के "विकल्प" प्रकार देखें कि यह कैसे किया जाना चाहिए। – MichaelGG

+0

संभावित डुप्लिकेट [बिना शून्य के भाषाओं के लिए सर्वश्रेष्ठ स्पष्टीकरण] (http://stackoverflow.com/questions/3989264/best-explanation-for-languages-without-null) – nawfal

उत्तर

-2

मुझे न्यूल का उपयोग पसंद है। यह थोड़ी देर के बाद से मैंने सी ++ में काम किया है, लेकिन इसने वापसी मूल्यों और संदर्भों के बारे में अपनी समस्याओं को ढूंढना और उन्हें ठीक करना बहुत आसान बना दिया है।

+0

बिंदु को याद करता है। –

2

मैं मानता हूं कि मैंने वास्तव में स्पेक # के बारे में बहुत कुछ नहीं पढ़ा है, लेकिन मुझे समझ में आया था कि NonNullable अनिवार्य रूप से एक विशेषता है जिसे आपने पैरामीटर पर रखा है, जरूरी नहीं कि एक परिवर्तनीय घोषणा पर; की तरह कुछ में अपने उदाहरण मुड़ें:

class Class { ... } 

void DoSomething(Class c) 
{ 
    if (c == null) return; 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

void main() { 
    Class c = nullptr; 
    // ... ... ... code ... 
    DoSomething(c); 
} 
युक्ति # साथ

, आप DoSomething चिह्नित कर रहे हैं कहने के लिए "पैरामीटर ग नल नहीं हो सकता"। ऐसा लगता है कि मेरे पास एक अच्छी सुविधा है, क्योंकि इसका मतलब है कि मुझे DoSomething() विधि में पहली पंक्ति की आवश्यकता नहीं है (जो लाइन भूलना आसान है, और DoSomething() के संदर्भ में पूरी तरह से अर्थहीन है।

6

मुझे आपका उदाहरण समझ में नहीं आता है। यदि आपका "= नया वर्ग()" शून्य न होने की जगह केवल प्लेसहोल्डर है, तो यह स्पष्ट रूप से एक बग है (मेरी आंखों के लिए)। यदि यह नहीं है, तो वास्तविक बग यह है कि "..." ने अपनी सामग्री को सही ढंग से सेट नहीं किया है, जो कि दोनों मामलों में बिल्कुल समान है।

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

मुझे नहीं लगता कि "नो नल" का बिंदु केवल एक पाठ खोज-और-प्रतिस्थापन करना है और उन्हें सभी खाली उदाहरणों में बनाना है। यह स्पष्ट रूप से बेकार है।बिंदु आपके कोड को ढांचा बनाना है ताकि आपके चर कभी भी ऐसे राज्य में न हों जहां वे बेकार/गलत मानों को इंगित करते हैं, जिनमें से NULL बस सबसे आम है।

+0

तो यदि कोई भाषा गैर-शून्य प्रकारों को लागू करती है, तो "कक्षा सी" जैसे बयान क्या होता है सी सेट करें? (मैं पूरी तरह से आपकी टिप्पणियों से सहमत हूं) – zildjohn01

+2

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

+1

वापस देख रहे हैं: एसक्यूएल सोचो। यदि आपके पास "न्यूल न्यूल" कॉलम है और इसके लिए गैर-शून्य मान निर्दिष्ट किए बिना रिकॉर्ड डालने का प्रयास करें, तो यह केवल एक त्रुटि उठाता है। – Ken

0

जैसा कि मैंने देखा है वहां दो क्षेत्र हैं जहां शून्य का उपयोग किया जाता है।

पहला मूल्य की अनुपस्थिति है। उदाहरण के लिए, एक बूलियन सत्य या गलत हो सकता है, या उपयोगकर्ता ने अभी तक एक सेटिंग नहीं चुनी है, इसलिए शून्य। यह उपयोगी और अच्छी बात है, लेकिन शायद मूल रूप से गलत तरीके से कार्यान्वित किया गया है और अब उस उपयोग को औपचारिक बनाने का प्रयास है। (वहाँ एक तीन राज्य तर्क के भाग के रूप सेट/सेट किए बिना राज्य, या अशक्त धारण करने के लिए एक दूसरे बूलियन होना चाहिए?)

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

तो, इनमें से कौन सा आप रुचि रखते हैं?

+0

# 2। – zildjohn01

2

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

जब आप कोई फ़ंक्शन परिभाषित करते हैं, तो आप इसके तर्कों को एनोटेट करते हैं। उदाहरण के लिए, निम्नलिखित कोड संकलन होगा

int f(@nullable Foo foo) { 
    if (foo == null) 
    return 0; 
    return foo.size(); 
}

हालांकि foo प्रविष्टि, नियंत्रण की गारंटी देता है के प्रवाह कि, जब आप foo.size() कहते हैं, foo nonnull है पर अशक्त हो सकता है।

लेकिन यदि आप शून्य के लिए चेक हटाते हैं, तो आपको संकलन-समय त्रुटि मिल जाएगी।

निम्नलिखित भी संकलन होगा, क्योंकि foo प्रवेश के समय nonnull है:

@nullable Foo foo; 
g(foo); // compiler error!

संकलक करता है:

int g(@nonnull Foo foo) { 
    return foo.size(); // OK 
}

हालांकि, अगर आप एक नल सूचक के साथ जी कॉल करने के लिए सक्षम नहीं होगा प्रत्येक फ़ंक्शन के लिए प्रवाह विश्लेषण, इसलिए यह पता लगाया जा सकता है कि @nullable @nonnull बन जाता है (उदाहरण के लिए, अगर एक बयान के अंदर जो शून्य के लिए जांचता है)। यह एक @nonnull सत्य परिभाषा भी स्वीकार करेगा बशर्ते इसे तुरंत शुरू किया जाए।

@nonnull Foo foo = new Foo();

my blog में इस विषय पर और भी बहुत कुछ है।

0

मैं वर्तमान में इस विषय पर सी # में काम कर रहा हूं। .NET के मान प्रकारों के लिए शून्य है, लेकिन संदर्भ प्रकार के लिए व्यस्त सुविधा मौजूद नहीं है।

मैंने संदर्भ प्रकारों के लिए NotNullable नहीं बनाया है, और डेटाटाइप डोमेन पर समस्या (यदि शून्य के लिए कोई और जांच नहीं) से समस्या को स्थानांतरित कर दिया है। यह एप्लिकेशन को रनटाइम में अपवाद फेंकने के लिए बनाता है और संकलन समय में नहीं।

12

इसका एक छोटे से अजीब है कि प्रतिक्रिया में चिह्नित "जवाब" में इस सूत्र वास्तव में पहले स्थान पर है, अर्थात् में अशक्त के साथ समस्या पर प्रकाश डाला गया:

मैं यह भी पाया है मेरी शून्य सूचक त्रुटियों का सबसे कि स्ट्रिंग.h, के कार्यों की वापसी के लिए की जांच करने के लिए भूलने से फ़ंक्शन को हल करें जहां NULL को संकेतक के रूप में उपयोग किया जाता है।

क्या यह अच्छा नहीं होगा अगर संकलक रनटाइम के बजाय संकलन समय पर इन प्रकार की त्रुटियों को पकड़ सके?

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

let findUser username = 
    let recordset = executeQuery("select * from users where username = @username") 
    if recordset.getCount() > 0 then 
     let user = initUser(recordset) 
     Some(user) 
    else 
     None 

उपयोगकर्ता ढूँढें प्रकार val findUser : string -> user option है, तो समारोह की वापसी प्रकार वास्तव में आपको बताता है कि यह एक शून्य मान लौट सकते हैं। कोड का उपभोग करने के लिए, आप दोनों कुछ और कोई भी मामलों को संभालने की जरूरत है:

match findUser "Juliet Thunderwitch" with 
| Some x -> print_endline "Juliet exists in database" 
| None -> print_endline "Juliet not in database" 

आप दोनों ही मामलों को संभाल नहीं है, तो कोड भी संकलन नहीं होंगे। तो टाइप-सिस्टम गारंटी देता है कि आपको कभी भी एक नल-रेफरेंस अपवाद नहीं मिलेगा, और यह गारंटी देता है कि आप हमेशा नल को संभालते हैं। और यदि कोई फ़ंक्शन user देता है, तो यह किसी ऑब्जेक्ट का वास्तविक उदाहरण होने की गारंटी देता है। त।

class Class { ... } 

void main() { 
    Class c = new Class(); // set to new Class() by default 
    // ... ... ... code ... 
    for(int i = 0; i < c.count; ++i) { ... } 
} 

प्रारंभ और अप्रारंभीकृत वस्तुओं एक ही डेटाप्रकार है, तो आप उन दोनों के बीच अंतर नहीं बता सकता:

अब हम ओ पी के नमूना कोड में समस्या देखते हैं। कभी-कभी, null object pattern उपयोगी हो सकता है, लेकिन उपरोक्त कोड दर्शाता है कि संकलक का यह निर्धारित करने का कोई तरीका नहीं है कि आप अपने प्रकार का सही तरीके से उपयोग कर रहे हैं या नहीं।

0

जब हम डोमेन ऑब्जेक्ट्स से निपट रहे हैं तो गैर-शून्य प्रकार मेरे लिए अधिक समझ में आते हैं। जब आप ऑब्जेक्ट्स में डेटाबेस टेबल मैप कर रहे हैं और आपके पास गैर-शून्य कॉलम हैं। मान लें कि आपके पास उपयोगकर्ता नामक एक टेबल है और इसमें कॉलम उपयोगकर्ता आईडी वर्कर (20) शून्य नहीं है;

उपयोगकर्ता आईडी स्ट्रिंग फ़ील्ड के साथ उपयोगकर्ता क्लास रखना इतना सुविधाजनक होगा जो शून्य नहीं है। आप संकलन समय पर कुछ बग को कम करते हैं।

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