क्या "और" का उपयोग उन परिस्थितियों में किया जाना चाहिए जहां नियंत्रण प्रवाह इसे बेमानी बनाता है?


18

मैं कभी-कभी निम्नलिखित उदाहरण के समान कोड पर ठोकर खाता हूं (यह फ़ंक्शन वास्तव में इस प्रश्न के दायरे से बाहर क्या है):

function doSomething(value) {
  if (check1(value)) {
    return -1;
  }
  else if (check2(value)) {
    return value;
  }
  else {
    return false;
  }
}

आप देख सकते हैं, if, else ifऔर elseबयानों के साथ संयोजन के रूप में उपयोग किया जाता है returnबयान। यह एक आकस्मिक पर्यवेक्षक के लिए काफी सहज लगता है, लेकिन मुझे लगता है कि यह (सॉफ्टवेयर डेवलपर के नजरिए से) else-s को ड्रॉप करने और इस तरह कोड को सरल बनाने के लिए अधिक सुरुचिपूर्ण होगा :

function doSomething(value) {
  if (check1(value)) {
    return -1;
  }
  if (check2(value)) {
    return value;
  }
  return false;
}

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

उपरोक्त में से कौन सा अच्छा कोडिंग अभ्यास अधिक फिट बैठता है? क्या कोड पठनीयता के संबंध में किसी भी विधि में कोई कमियां हैं?

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


14
यह elseएक कम मुद्दा है, बड़ी समस्या यह है कि आप स्पष्ट रूप से एक ही फ़ंक्शन से दो डेटा प्रकार वापस कर रहे हैं, जो फ़ंक्शन के एपीआई को अप्रत्याशित बनाता है।
एंडी

3
E_CLEARLY_NOTADUPE
kojiro 19

3
@ डेविडपैकर: कम से कम दो; तीन हो सकते हैं। -1एक संख्या है, falseएक बूलियन है, और valueयहां निर्दिष्ट नहीं है इसलिए यह किसी भी प्रकार की वस्तु हो सकती है।
2129 बजे Y29295

1
@ Yay295 मुझे उम्मीद थी कि valueवास्तव में एक पूर्णांक है। अगर यह कुछ भी हो सकता है तो यह और भी बुरा है।
एंडी

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

जवाबों:


23

मैं बिना एक के elseऔर यहाँ क्यों पसंद है:

function doSomething(value) {
  //if (check1(value)) {
  //  return -1;
  //}
  if (check2(value)) {
    return value;
  }
  return false;
}

क्योंकि ऐसा करने से कुछ भी नहीं टूटता था।

सभी रूपों में इस पर निर्भरता से नफरत है (एक फ़ंक्शन का नामकरण सहित check2())। अलग-थलग हो सकते हैं। कभी-कभी आपको आवश्यकता होती है elseलेकिन मैं यहाँ नहीं देख सकता हूँ।


मैं आम तौर पर यह भी पसंद करता हूं, यहां बताए गए कारण के लिए। हालाँकि, मैं आमतौर पर कोड को पढ़ते समय यह स्पष्ट करने ifके } //elseलिए प्रत्येक ब्लॉक के करीब एक टिप्पणी रखता हूं , कि ifकोड ब्लॉक के बाद एकमात्र इच्छित निष्पादन है यदि ifकथन में स्थिति झूठी थी। इस तरह के कुछ के बिना, खासकर अगर ifब्लॉक के भीतर कोड अधिक जटिल हो जाता है, तो यह स्पष्ट नहीं हो सकता है कि जो कोई भी कोड को बनाए रख रहा है वह यह है कि ifयह ifशर्त सही होने पर ब्लॉक को अतीत में निष्पादित नहीं करना था ।
मकेन

@ माकन आप एक अच्छा मुद्दा उठाएं। एक जिसे मैं नजरअंदाज करना चाह रहा था। मेरा यह भी मानना ​​है ifकि यह स्पष्ट करने के लिए कि कोड का यह खंड किया जाता है और संरचना समाप्त हो जाने के बाद कुछ किया जाना चाहिए । ऐसा करने के लिए मैं वही करता हूं जो मैंने यहां नहीं किया है (क्योंकि मैं अन्य बदलाव करके ओपी के मुख्य बिंदु से विचलित नहीं करना चाहता था)। मैं सबसे सरल काम करता हूं जो विचलित किए बिना वह सब हासिल करता है। मैं एक रिक्त रेखा जोड़ता हूं।
कैंडिड_ऑरेंज

27

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

if (x < 0) {
    return false;
} else if (x > 0) {
    return true;
} else {
    throw new IllegalArgumentException();
}

यहां आप स्पष्ट रूप xसे सभी तीन मामलों में मूल्य पर निर्भर करते हैं । यदि आप अंतिम को छोड़ elseदेंगे, तो यह कम स्पष्ट होगा।

यदि आपके मामले सीधे एक दूसरे पर निर्भर नहीं हैं, तो इसे छोड़ दें:

if (x < 0) {
    return false;
}
if (y < 0) {
    return true;
}
return false;

बिना संदर्भ के इसे सरल उदाहरण में दिखाना कठिन है, लेकिन मुझे आशा है कि आपको मेरी बात मिल जाएगी।


6

मैं दूसरा विकल्प पसंद करता हूं ( ifsबिना else ifऔर जल्दी से अलग return) लेकिन BUT वह है जब तक कोड ब्लॉक कम होते हैं

यदि कोड ब्लॉक लंबे हैं, तो इसका उपयोग करना बेहतर है else if, क्योंकि दूसरे आपके पास कोड से बाहर निकलने के कई बिंदुओं की स्पष्ट समझ नहीं होगी।

उदाहरण के लिए:

function doSomething(value) {
  if (check1(value)) {
    // ...
    // imagine 200 lines of code
    // ...
    return -1;
  }
  if (check2(value)) {
    // ...
    // imagine 150 lines of code
    // ...
    return value;
  }
  return false;
}

उस मामले में, यह बेहतर उपयोग है else if, रिटर्न कोड को एक चर में स्टोर करें और अंत में सिर्फ एक रिटर्न वाक्य रखें।

function doSomething(value) {
  retVal=0;
  if (check1(value)) {
    // ...
    // imagine 200 lines of code
    // ...
    retVal=-1;
  } else if (check2(value)) {
    // ...
    // imagne 150 lines of code
    retVal=value;
  }
  return retVal;
}

लेकिन जैसा कि एक के लिए कार्यों को छोटा करने का प्रयास करना चाहिए, मैं कहूंगा कि इसे छोटा रखें और अपने पहले कोड स्निपेट की तरह जल्दी बाहर निकलें।


1
मैं आपके आधार से सहमत हूं, लेकिन जब तक हम चर्चा कर रहे हैं कि कोड कैसे होना चाहिए, तो क्या हम भी सहमत हो सकते हैं कि कोड ब्लॉक वैसे भी कम होना चाहिए? मुझे लगता है कि कोड का एक लंबा ब्लॉक होना गलत है, अगर मुझे चुनना है तो इसका उपयोग करने के बजाय कार्यों में नहीं टूटना चाहिए।
कोजिरो 19

1
एक जिज्ञासु तर्क। return3 लाइनों के भीतर है ifतो यह else ifकोड की 200 लाइनों के बाद भी अलग नहीं है । आपके द्वारा यहां प्रस्तुत एकल वापसी शैली सी और अन्य भाषाओं की परंपरा है जो अपवादों के साथ त्रुटियों की रिपोर्ट नहीं करते हैं। बिंदु था संसाधनों को साफ करने के लिए एक ही जगह बनाना। अपवाद भाषाएं इसके लिए एक finallyब्लॉक का उपयोग करती हैं। मुझे लगता है कि यह एक विराम बिंदु डालने के लिए भी जगह बनाता है यदि आपका डिबगर अभ्यस्त आपको कर्ली ब्रेस को बंद करने वाले कार्यों में से एक में डाल देता है।
कैंडिड_ऑरेंज

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

2
मेरी राय में यह लंबे ब्लॉक के लिए और भी बुरा है। मैं जितनी जल्दी हो सके बाहरी संदर्भ के कार्यों से बाहर निकलने की कोशिश करता हूं।
एंडी

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

4

मैं विभिन्न परिस्थितियों में दोनों का उपयोग करता हूं। एक सत्यापन जांच में, मैं बाकी को छोड़ देता हूं। एक नियंत्रण प्रवाह में, मैं दूसरे का उपयोग करता हूं।

bool doWork(string name) {
  if(name.empty()) {
    return false;
  }

  //...do work
  return true;
}

बनाम

bool doWork(int value) {
  if(value % 2 == 0) {
    doWorkWithEvenNumber(value);
  }
  else {
    doWorkWithOddNumber(value);
  }
}

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


0

एकमात्र स्थिति जिसे मैंने कभी देखा है वह वास्तव में इस तरह का कोड है:

List<?> toList() {
    if (left != null && right != null) {
        Arrays.asList(merge(left, right));
    }
    if (left != null) {
        return Arrays.asList(left);
    }
    if (right != null) {
        return Arrays.asList(right);
    }
    return Arrays.asList();
}

यहाँ स्पष्ट रूप से कुछ गड़बड़ है। समस्या यह है, यह स्पष्ट नहीं है कि अगर returnजोड़ा या Arrays.asListहटाया जाना चाहिए । आप संबंधित विधियों के गहन निरीक्षण के बिना इसे ठीक नहीं कर सकते। आप इस अस्पष्टता से हमेशा बच सकते हैं अगर पूरी तरह से निकास का उपयोग करके-और ब्लॉक। इस:

List<?> toList() {
    if (left != null && right != null) {
        Arrays.asList(merge(left, right));
    } else if (left != null) {
        return Arrays.asList(left);
    } else if (right != null) {
        return Arrays.asList(right);
    } else {
        return Arrays.asList();
    }
}

जब तक आप पहली बार में स्पष्ट रिटर्न नहीं जोड़ेंगे, तब तक (सांख्यिकीय रूप से जाँच की गई भाषाओं में) संकलन नहीं करेंगे if

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

List<?> toList() {
    if (left == null || right == null) {
        throw new IllegalStateException()
    }
    // ...
    // long method
    // ...
}

-2

यदि आप कोड के माध्यम से और बुरे अभ्यास का पालन करने की कोशिश कर रहे हैं तो इस तरह समारोह से तीन बाहर निकलना वास्तव में भ्रामक है।

यदि आपके पास फ़ंक्शन के लिए एकल निकास बिंदु है, तो एलस की आवश्यकता है।

var result;
if(check1(value)
{
    result = -1;
}
else if(check2(value))
{
    result = value;
}
else 
{
    result = 0;
}
return result;

वास्तव में आगे भी जाने देता है।

var result = 0;
var c1 = check1(value);
var c2 = check2(value);

if(c1)
{
    result = -1;
}
else if(c2)
{
    result = value;
}

return result;

पर्याप्त रूप से आप इनपुट सत्यापन पर एक एकल प्रारंभिक रिटर्न के लिए बहस कर सकते हैं। बस पूरे बल्क को लपेटने से बचें अगर आपके तर्क में यदि।


3
यह शैली स्पष्ट संसाधन प्रबंधन वाली भाषाओं से आती है। आवंटित संसाधनों को मुक्त करने के लिए एकल बिंदु की आवश्यकता थी। स्वचालित संसाधन प्रबंधन वाली भाषाओं में एकल वापसी बिंदु उतना महत्वपूर्ण नहीं है। आपको चर की संख्या और दायरे को कम करने पर ध्यान देना चाहिए।
बंथर

a: प्रश्न में कोई भाषा निर्दिष्ट नहीं है। b: मुझे लगता है कि आप इस पर गलत हैं। सिंगल रिटर्न के बहुत सारे अच्छे कारण हैं। यह जटिलता को कम करता है और पठनीयता को बढ़ाता है
इवान

1
कभी-कभी यह जटिलता को कम करता है, कभी-कभी इसे बढ़ाता है। देखें wiki.c2.com/?rrowAntiPattern
रॉबर्ट जॉनसन

नहीं, मुझे लगता है कि यह हमेशा चक्रीय जटिलता को कम करता है, मेरा दूसरा उदाहरण देखें। check2 हमेशा चलता है
Ewan

प्रारंभिक रिटर्न होना एक अनुकूलन है जो कुछ कोड को एक सशर्त में ले जाकर कोड को जटिल करता है
ईवान

-3

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

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


3
जबकि मैं आपसे सहमत होने के लिए ऐसा करता हूं, यह एक जनमत सर्वेक्षण नहीं है। कृपया अपने दावों का समर्थन करें या मतदाता आपसे विनम्र व्यवहार नहीं करेंगे।
कैंडिड_ओरेंज
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.