क्या "चर संभव के रूप में सबसे छोटे दायरे में रहना चाहिए" मामले में "चर संभव हो तो मौजूद नहीं होना चाहिए" शामिल हैं?


32

" उदाहरण चर पर स्थानीय चर पसंद करने के लिए तर्क " पर स्वीकृत उत्तर के अनुसार , चर संभव सबसे कम दायरे में रहना चाहिए।
मेरी व्याख्या में समस्या को सरल बनाएं, इसका मतलब है कि हमें इस तरह के कोड को रिफ्लेक्टर करना चाहिए:

public class Main {
    private A a;
    private B b;

    public ABResult getResult() {
        getA();
        getB();
        return ABFactory.mix(a, b);
    }

    private getA() {
      a = SomeFactory.getA();
    }

    private getB() {
      b = SomeFactory.getB();
    }
}

कुछ इस तरह से:

public class Main {
    public ABResult getResult() {
        A a = getA();
        B b = getB();
        return ABFactory.mix(a, b);
    }

    private getA() {
      return SomeFactory.getA();
    }

    private getB() {
      return SomeFactory.getB();
    }
}

लेकिन "चर" की "भावना" के अनुसार संभव के रूप में सबसे छोटे दायरे में रहना चाहिए "," चर कभी नहीं "" छोटे चर "की तुलना में छोटा गुंजाइश है"? इसलिए मुझे लगता है कि ऊपर दिए गए संस्करण को फिर से भरना चाहिए:

public class Main {
    public ABResult getResult() {
        return ABFactory.mix(getA(), getB());
    }

    private getA() {
      return SomeFactory.getA();
    }

    private getB() {
      return SomeFactory.getB();
    }
}

ताकि getResult()किसी भी स्थानीय चर बिल्कुल नहीं है। क्या यह सच है?


72
स्पष्ट चर बनाना उनके नाम रखने के लाभ के साथ आता है। कुछ चर का परिचय जल्दी से एक पठनीय में एक अपारदर्शी विधि बदल सकते हैं।
जारेड गोगुएन

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

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

2
@JaredGoguen स्पष्ट चर बनाना उनके नाम रखने और उन्हें नाम देने में सक्षम होने के लाभ के साथ आता है।
बरगी

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

जवाबों:


110

नहीं, कई कारण हैं:

  1. सार्थक नामों के साथ विविधताएं कोड को समझना आसान बना सकती हैं।
  2. छोटे चरणों में जटिल सूत्रों को तोड़कर कोड को पढ़ना आसान बना सकते हैं।
  3. भंडारित करता है।
  4. वस्तुओं का संदर्भ रखना ताकि उन्हें एक से अधिक बार उपयोग किया जा सके।

और इसी तरह।


22
यह भी ध्यान देने योग्य है: मूल्य को ध्यान में रखते हुए मेमोरी में स्टोर किया जा रहा है, इसलिए यह वास्तव में वैसे भी उसी दायरे के साथ समाप्त होता है। हो सकता है कि इसे नाम दिया जाए (जिन कारणों के लिए रॉबर्ट का उल्लेख है)!
है_Factor

5
@Maybe_Factor प्रदर्शन कारणों के लिए दिशानिर्देश वास्तव में नहीं है; यह कोड को बनाए रखना कितना आसान है। लेकिन फिर भी इसका मतलब है कि सार्थक स्थानीय लोग एक बड़ी अभिव्यक्ति से बेहतर हैं, जब तक कि आप केवल नामांकित और डिज़ाइन किए गए कार्यों की रचना नहीं कर रहे हैं (उदाहरण के लिए ऐसा करने का कोई कारण नहीं है var taxIndex = getTaxIndex();)।
लुआं

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

8
कंपाइलर 3 & 4. की देखभाल करेगा
स्टॉप हार्मिंग मोनिका

9
नंबर 4 शुद्धता के लिए महत्वपूर्ण हो सकता है। यदि फ़ंक्शन कॉल का मान परिवर्तित हो सकता है (जैसे now()) चर को हटाने और विधि को एक से अधिक बार कॉल करने के परिणामस्वरूप बग हो सकते हैं। यह एक ऐसी स्थिति बना सकता है जो वास्तव में सूक्ष्म है और डीबग करना कठिन है। यह स्पष्ट लग सकता है, लेकिन यदि आप चर को हटाने के लिए एक अंधे परावर्तन मिशन पर हैं, तो खामियों को शुरू करना आसान है।
जिमीजैम

16

सहमत हैं, चर जो आवश्यक नहीं हैं और कोड की पठनीयता में सुधार नहीं करते हैं, से बचा जाना चाहिए। कोड में दिए गए बिंदु पर जितने अधिक चर होंगे, उतने ही जटिल कोड को समझना होगा।

मुझे वास्तव में चर का aऔर bआपके उदाहरण में लाभ दिखाई नहीं देता है , इसलिए मैं चर के बिना संस्करण लिखूंगा। दूसरी ओर फ़ंक्शन पहले स्थान पर इतना सरल है कि मुझे नहीं लगता कि यह बहुत मायने रखता है।

यह एक समस्या के रूप में अधिक हो जाता है जब फ़ंक्शन प्राप्त होता है और अधिक चर दायरे में होते हैं।

उदाहरण के लिए यदि आपके पास है

    a=getA();
    b=getB();
    m = ABFactory.mix(a,b);

एक बड़े फ़ंक्शन के शीर्ष पर, आप एक के बजाय तीन चर पेश करके बाकी कोड को समझने के मानसिक बोझ को बढ़ाते हैं। आपको यह देखने के लिए बाकी कोड के माध्यम से पढ़ना होगा कि क्या इसका उपयोग किया जाता है aया नहीं b। स्थानीय लोग जो अधिक दायरे में हैं, वे समग्र पठनीयता के लिए खराब हैं।

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


2
बेशक, इस बिंदु से एक विधि इतनी लंबी हो जाती है कि स्थानीय लोगों की संख्या आसानी से बनाए रखने के लिए बहुत बड़ी है, आप शायद इसे वैसे भी तोड़ना चाहते हैं।
लुआं

4
"एक्सट्रॉनिक" चर के लाभों पर जैसे var result = getResult(...); return result;कि आप एक ब्रेकपॉइंट डाल सकते हैं returnऔर सीख सकते हैं कि वास्तव resultमें क्या है।
जोकर_vD

5
@ जोकर_वीडी: इसके नाम के योग्य डिबगर आपको वैसे भी यह सब करने में सक्षम होना चाहिए (किसी फ़ंक्शन के परिणामों को स्थानीय चर में संग्रहीत किए बिना फ़ंक्शन फ़ंक्शन पर ब्रेकपॉइंट सेट करके देखें)।
क्रिश्चियन हैकल

2
@ChristianHackl बहुत कम डिबग्रेसर आपको ऐसा करने के लिए संभवतया जटिल घड़ियों की स्थापना के बिना करते हैं, जो इसमें जोड़ने के लिए समय लेते हैं (और यदि कार्यों के दुष्प्रभाव हैं तो सब कुछ टूट सकता है)। मैं सप्ताह के किसी भी दिन डिबगिंग के लिए चर संस्करण के साथ ले जाऊंगा।
गाबे सांचे

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

11

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

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

आइए एक नजर डालते हैं अपने शुरुआती getResultतरीके पर:

public ABResult getResult() {
    getA();
    getB();
    return ABFactory.mix(this.a, this.b);
}

अब, नाम getAऔर सुझाव देgetB सकते हैं कि वे असाइन करेंगे this.aऔर this.b, हम केवल देखने से सुनिश्चित नहीं हो सकते हैं getResult। इस प्रकार, यह संभव है कि this.aऔर this.bमें पारित कर दिया मूल्यों mixविधि के बजाय राज्य से आते हैं thisपहले से वस्तु getResultलागू किया गया था, जो बाद से ग्राहकों को नियंत्रित कैसे और कब पद्धतियों को बुलाया जाता भविष्यवाणी करना असंभव है।

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

इस प्रकार, क्लास-स्कोप से लोकल-स्कोप (साथ ही साथ लूप के बाहर से अंदर तक ले जाने योग्य) में बदलाव करने (संशोधित करने) के लिए एक महत्वपूर्ण लाभ यह है कि यह नियंत्रण-प्रवाह तर्क को सरल करता है।

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

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


2

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

(reduce (fn [map string] (assoc map string (inc (map string 0))) 

या कुछ LINQ:

var query2 = mydb.MyEntity.Select(x => x.SomeProp).AsEnumerable().Where(x => x == "Prop");

या Node.js:

 return visionFetchLabels(storageUri)
    .then(any(isCat))
    .then(notifySlack(secrets.slackWebhook, `A cat was posted: ${storageUri}`))
    .then(logSuccess, logError)
    .then(callback)

अंतिम किसी भी मध्यवर्ती चर के बिना पिछले फ़ंक्शन के परिणाम पर एक फ़ंक्शन को कॉल करने की एक श्रृंखला है। उन्हें प्रस्तुत करने से यह बहुत कम स्पष्ट होगा।

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

एफ # का पाइप ऑपरेटर |>आंशिक रूप से उपयोगी है क्योंकि यह आपको बाएं से दाएं चीजों को लिखने की अनुमति देता है जो अन्यथा दाएं-बाएं होना चाहिए।


2
मैं साधारण LINQ अभिव्यक्तियों या लैम्ब्डा में अपने चर नाम के रूप में अंडरस्कोर का उपयोग करने के लिए लिया है। myCollection.Select(_ => _.SomeProp).Where(_ => _.Size > 4);
ग्राहम

यकीन नहीं होता कि यह ओपी के सवाल का थोड़ा-बहुत जवाब देता है ...
एसी

1
क्यों घटता है? मेरे लिए एक अच्छा जवाब की तरह लगता है, भले ही यह सीधे सवाल का जवाब नहीं है यह अभी भी उपयोगी जानकारी है
रेगेगिटेर

1

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


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

1

कार्यों ( विधियों ) पर विचार करें । वहां यह न तो सबसे छोटे संभव उप कोड में कोड को विभाजित कर रहा है, न ही कोड का सबसे बड़ा सिंगलटन टुकड़ा।

यह एक परिवर्तनशील सीमा है, जिसमें तार्किक कार्यों को, उपभोग्य टुकड़ों में परिसीमित किया जाता है।

वैरिएबल के लिए भी यही है । तार्किक भागों में तार्किक संरचनाओं को इंगित करते हुए। या बस मापदंडों का नामकरण (बताते हुए):

boolean automatic = true;
importFile(file, automatic);

लेकिन निश्चित रूप से शीर्ष पर एक घोषणा है, और दो सौ लाइनों के आगे पहला उपयोग आजकल खराब शैली के रूप में स्वीकार किया जाता है। यह स्पष्ट रूप से है कि "चर को सबसे छोटे दायरे में रहना चाहिए" कहने का इरादा है। बहुत निकट की तरह "चर का पुन: उपयोग न करें।"


1

व्हाट्सएप कुछ गायब है क्योंकि NO का कारण डिबगिंग / रीडाबिलिटी है। उस के लिए कोड को अनुकूलित किया जाना चाहिए, और स्पष्ट और संक्षिप्त नाम बहुत मदद करते हैं जैसे कि एक 3 तरह की कल्पना करें

if (frobnicate(x) && (get_age(x) > 2000 || calculate_duration(x) < 100 )

यह पंक्ति छोटी है, लेकिन पहले से ही कठिन है। कुछ और पैरामीटर्स जोड़ें, और यह कि यदि कई लाइनों को फैलाया जाए।

can_be_frobnicated = frobnicate(x)
is_short_lived_or_ancient = get_age(x) > 2000 || calculate_duration(x) < 100
if (can_be_frobnicated || is_short_lived_or_ancient )

मुझे इस तरह से पढ़ना और अर्थ संप्रेषित करना आसान लगता है - इसलिए मुझे मध्यवर्ती चरों की कोई समस्या नहीं है।

एक अन्य उदाहरण R जैसी भाषाएं होंगी, जहां अंतिम पंक्ति स्वचालित रूप से रिटर्न मान है:

some_func <- function(x) {
    compute(x)
}

यह खतरनाक है, क्या वापसी की उम्मीद है या जरूरत है? यह स्पष्ट है:

some_func <- function(x) {
   rv <- compute(x)
   return(rv)
}

हमेशा की तरह, यह एक निर्णय कॉल है - अगर वे पढ़ने में सुधार नहीं करते हैं, तो मध्यस्थ चर को समाप्त करें, अन्यथा उन्हें रखें या परिचय दें।

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


0

सिर्फ अपने शीर्षक का संदर्भ: बिल्कुल, यदि कोई चर अनावश्यक है तो उसे हटा दिया जाना चाहिए।

लेकिन "अनावश्यक" का मतलब यह नहीं है कि चर का उपयोग किए बिना एक समान कार्यक्रम लिखा जा सकता है, अन्यथा हमें बताया जाएगा कि हमें बाइनरी में सब कुछ लिखना चाहिए।

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

यदि आपका उदाहरण कोड ठीक-ठीक दर्शाया गया है, तो मैं दो निजी तरीकों से छुटकारा पाने का सुझाव दूंगा, लेकिन इस बात से कोई सरोकार नहीं होगा कि क्या आपने फ़ैक्टरी कॉल के परिणाम को किसी स्थानीय वैरिएबल में सहेजा है या उन्हें मिश्रण के लिए तर्क के रूप में इस्तेमाल किया है तरीका।

कोड पठनीयता सही ढंग से काम करने के अलावा सब कुछ ट्रम्प करती है (सही तरीके से स्वीकार्य प्रदर्शन मानदंड शामिल हैं, जो शायद ही कभी "जितनी जल्दी हो सके")।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.