यदि कथन - शॉर्ट सर्किट मूल्यांकन बनाम पठनीयता


90

कभी-कभी, एक ifबयान बल्कि जटिल या लंबा हो सकता है, इसलिए पठनीयता के लिए जटिल कॉल को निकालने से पहले बेहतर है if

इस प्रकार:

if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
    // do stuff
}

इस मामले में

bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();

if (b1 || b2)
{
    //do stuff
}

(बशर्ते उदाहरण यह बुरा नहीं है , यह सिर्फ दृष्टांत के लिए है ... कई तर्कों के साथ अन्य कॉल की कल्पना करें, आदि)

लेकिन इस निष्कर्षण के साथ मैंने शॉर्ट सर्किट मूल्यांकन (SCE) खो दिया।

  1. क्या मैं वास्तव में हर बार एससीई खो देता हूं? क्या कुछ परिदृश्य है जहां संकलक को "इसे अनुकूलित" करने की अनुमति है और अभी भी एससीई प्रदान करते हैं?
  2. क्या SCE को खोए बिना दूसरे स्निपेट की बेहतर पठनीयता को बनाए रखने के तरीके हैं?

20
अभ्यास से पता चलता है कि प्रदर्शन के बारे में अधिकांश उत्तर आप यहां या अन्य स्थानों पर देखेंगे, ज्यादातर मामलों में गलत हैं (4 गलत 1 सही)। मेरी सलाह हमेशा एक रूपरेखा है और इसे स्वयं जांचें, आप "समय से पहले अनुकूलन" से बचेंगे और नया सामान सीखेंगे।
मारेक आर 10

25
@MarekR केवल प्रदर्शन के बारे में नहीं है, यह OtherCunctionCall में संभावित दुष्प्रभावों के बारे में है ...
relaxxx

3
@ अन्य साइटों का जिक्र करते हुए, अक्सर यह कहना मददगार होता है कि क्रॉस-पोस्टिंग पर रोक लगा दी जाती है
gnat

7
यदि पठनीयता आपकी प्राथमिक चिंता है, तो एक सशर्त के अंदर होने वाले दुष्प्रभावों के साथ कार्यों को न बुलाएं
Morgen

3
संभावित करीबी मतदाता: प्रश्न को फिर से पढ़ें। भाग (1) राय आधारित नहीं है , जबकि भाग (2) आसानी से एक संपादन के माध्यम से राय आधारित हो सकता है जो किसी भी "सर्वोत्तम अभ्यास" के संदर्भ को हटा देता है, जैसा कि मैं करने वाला हूं।
डुप्लोड

जवाबों:


119

एक प्राकृतिक समाधान इस तरह दिखेगा:

bool b1 = SomeCondition();
bool b2 = b1 || SomeOtherCondition();
bool b3 = b2 || SomeThirdCondition();
// any other condition
bool bn = bn_1 || SomeFinalCondition();

if (bn)
{
  // do stuff
}

यह समझने में आसान होने, सभी मामलों पर लागू होने और शॉर्ट सर्किट व्यवहार होने के फायदे हैं।


यह मेरा प्रारंभिक समाधान था: विधि कॉल और फॉर-लूप निकायों में एक अच्छा पैटर्न निम्नलिखित है:

if (!SomeComplicatedFunctionCall())
   return; // or continue

if (!SomeOtherComplicatedFunctionCall())
   return; // or continue

// do stuff

शॉर्टक्रिसिट मूल्यांकन के समान अच्छा प्रदर्शन लाभ प्राप्त करता है, लेकिन कोड अधिक पठनीय लगता है।


4
@relaxxx: मैं फिर से मिलता हूं, लेकिन "बाद में करने के लिए अधिक सामान if" भी एक संकेत है कि आपका फ़ंक्शन या विधि बहुत बड़ी है, और छोटे लोगों में विभाजित होना चाहिए। यह हमेशा सबसे अच्छा तरीका नहीं है लेकिन बहुत बार है!
nperson325681

2
यह श्वेत सूची सिद्धांत का उल्लंघन करता है
जूलिनॉर

13
@JoulinRouge: दिलचस्प है, मैंने इस सिद्धांत के बारे में कभी नहीं सुना था। मैं स्वयं पठनीयता पर लाभ के लिए इस "शॉर्ट-सर्किट" दृष्टिकोण को पसंद करता हूं: यह इंडेंटेशन को कम करता है और इस संभावना को समाप्त करता है कि इंडेंट ब्लॉक के बाद कुछ होता है।
मैथ्यू एम।

2
क्या यह अधिक पठनीय है? b2ठीक से नाम और आप मिल जाएगा someConditionAndSomeotherConditionIsTrue, सुपर सार्थक नहीं। इसके अलावा, मुझे इस अभ्यास के दौरान अपने मानसिक स्टैक पर चर का एक समूह रखना होगा (और जब तक मैं इस दायरे में काम करना बंद नहीं कर देता)। मैं SJuan762 नंबर के समाधान के साथ जाऊंगा या एक समारोह में पूरी बात रखूंगा।
नाथन कूपर

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

31

मैं कई लाइनों पर स्थितियों को तोड़ने के लिए हूँ, यानी:

if( SomeComplicatedFunctionCall()
 || OtherComplicatedFunctionCall()
  ) {

यहां तक ​​कि कई ऑपरेटरों (और&) के साथ काम करते समय आपको बस प्रत्येक जोड़ी कोष्ठक के साथ इंडक्शन को आगे बढ़ाने की आवश्यकता होती है। SCE अभी भी अंदर है - चर का उपयोग करने की आवश्यकता नहीं है। इस तरह से कोड लिखना इसने मुझे पहले से ही वर्षों के लिए बहुत अधिक पठनीय बना दिया। अधिक जटिल उदाहरण:

if( one()
 ||( two()> 1337
  &&( three()== 'foo'
   || four()
    )
   )
 || five()!= 3.1415
  ) {

28

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

bool b = SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
if (b && some_other_expression) { ... }

यदि आपके पास C ++ 11 सक्षम कंपाइलर हैं, तो आप उपरोक्त के समान कार्यों में अभिव्यक्तियों को संयोजित करने के लिए लैम्बडा एक्सप्रेशन का उपयोग कर सकते हैं :

auto e = []()
{
    return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
};

if (e() && some_other_expression) { ... }

21

1) हां, अब आपके पास SCE नहीं है। अन्यथा, आप ऐसा होता

bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();

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

2) यह राय आधारित है, लेकिन यथोचित जटिल अभिव्यक्तियों के लिए आप कर सकते हैं:

if (SomeComplicatedFunctionCall()
    || OtherComplicatedFunctionCall()) {

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


21

आप भी उपयोग कर सकते हैं:

bool b = someComplicatedStuff();
b = b || otherComplicatedStuff(); // it has to be: b = b || ...;  b |= ...; is bitwise OR and SCE is not working then 

और SCE काम करेगा।

लेकिन यह उदाहरण के लिए बहुत अधिक पठनीय नहीं है:

if (
    someComplicatedStuff()
    ||
    otherComplicatedStuff()
   )

3
मैं एक बिटवाइज़र ऑपरेटर के साथ बूलियन के संयोजन के लिए उत्सुक नहीं हूँ। यह मुझे अच्छी तरह से टाइप नहीं लगता है। आम तौर पर मैं जो कुछ भी सबसे अधिक पठनीय दिखता है उसका उपयोग करता हूं जब तक कि मैं बहुत कम स्तर और प्रोसेसर चक्र की गणना नहीं कर रहा हूं।
चींटी

3
मैंने विशिष्ट रूप से उपयोग किया है b = b || otherComplicatedStuff();और @SargeBorsch SCE को हटाने के लिए एक संपादन करता है। उस बदलाव के बारे में मुझे सूचित करने के लिए धन्यवाद @Ant।
KIIV

14

1) क्या मैं वास्तव में हर बार एससीई खो देता हूं? संकलक क्या कुछ परिदृश्य को "इसे अनुकूलित करें" और अभी भी SCE प्रदान करने की अनुमति है?

मुझे नहीं लगता कि इस तरह के अनुकूलन की अनुमति है; विशेष रूप OtherComplicatedFunctionCall()से कुछ दुष्प्रभाव हो सकते हैं।

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

मैं इसे वर्णनात्मक नाम के साथ एक फ़ंक्शन या एक चर में रिफ्लेक्टर करना पसंद करता हूं; जो शॉर्ट सर्किट मूल्यांकन और पठनीयता दोनों को संरक्षित करेगा:

bool getSomeResult() {
    return SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall();
}

...

if (getSomeResult())
{
    //do stuff
}

और हम को लागू के रूप में getSomeResult()के आधार पर SomeComplicatedFunctionCall()और OtherComplicatedFunctionCall(), हम उन्हें रिकर्सिवली विघटित कर सकता अगर वे अब भी जटिल कर रहे हैं।


2
मुझे यह पसंद है क्योंकि आप रैपर फ़ंक्शन को एक वर्णनात्मक नाम देकर कुछ पठनीयता प्राप्त कर सकते हैं (यद्यपि शायद getSomeResult नहीं है), बहुत सारे अन्य उत्तर वास्तव में कुछ भी मूल्य नहीं जोड़ते हैं
aw04

9

1) क्या मैं वास्तव में हर बार एससीई खो देता हूं? संकलक क्या कुछ परिदृश्य को "इसे अनुकूलित करें" और अभी भी SCE प्रदान करने की अनुमति है?

नहीं, तुम नहीं, लेकिन यह अलग तरह से लागू किया जाता है:

if (SomeComplicatedFunctionCall() || OtherComplicatedFunctionCall())
{
    // do stuff
}

OtherComplicatedFunctionCall()अगर SomeComplicatedFunctionCall()रिटर्न सही है तो यहां कंपाइलर भी नहीं चलेगा ।

bool b1 = SomeComplicatedFunctionCall();
bool b2 = OtherComplicatedFunctionCall();

if (b1 || b2)
{
    //do stuff
}

इधर, दोनों कार्यों जाएगा चलाने क्योंकि वे में संग्रहित किया जा करने के लिए है b1और b2। एफएफ b1 == trueतो b2का मूल्यांकन नहीं किया जाएगा (एससीई)। लेकिन OtherComplicatedFunctionCall()पहले ही चला दिया गया है।

यदि b2कहीं और उपयोग किया जाता है तो कंपाइलर पर्याप्त स्मार्ट हो सकता है यदि फ़ंक्शन में इनलाइन कॉल नहीं है यदि फ़ंक्शन का कोई अवलोकन साइड-इफेक्ट नहीं है।

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

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


8

एक और संभावना है कि शॉर्ट सर्किट और एक ही स्थान पर स्थितियां हैं:

bool (* conditions [])()= {&a, &b, ...}; // list of conditions
bool conditionsHold = true;
for(int i= 0; i < sizeOf(conditions); i ++){
     if (!conditions[i]()){;
         conditionsHold = false;
         break;
     }
}
//conditionsHold is true if all conditions were met, otherwise false

आप लूप को एक फ़ंक्शन में रख सकते हैं और फ़ंक्शन को शर्तों की एक सूची को स्वीकार करने और बूलियन मान को आउटपुट करने दें।


1
@Erbureth नहीं वे नहीं हैं। सरणी के तत्व फ़ंक्शन पॉइंटर्स हैं, वे तब तक निष्पादित नहीं होते हैं जब तक कि फ़ंक्शन को लूप में नहीं बुलाया जाता है।
बरमार

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

4

बहुत अजीब: आप पठनीयता के बारे में बात कर रहे हैं जब कोई भी कोड के भीतर टिप्पणी के उपयोग का उल्लेख नहीं करता है:

if (somecomplicated_function() || // let me explain what this function does
    someother_function())         // this function does something else
...

इसके शीर्ष पर, मैं हमेशा कुछ फ़ंक्शन के साथ, फ़ंक्शन के बारे में, अपने इनपुट और आउटपुट के बारे में, और कभी-कभी मैं एक उदाहरण देता हूं, जैसा कि आप यहां देख सकते हैं:

/*---------------------------*/
/*! interpolates between values
* @param[in] X_axis : contains X-values
* @param[in] Y_axis : contains Y-values
* @param[in] value  : X-value, input to the interpolation process
* @return[out]      : the interpolated value
* @example          : interpolate([2,0],[3,2],2.4) -> 0.8
*/
int interpolate(std::vector<int>& X_axis, std::vector<int>& Y_axis, int value)

स्पष्ट रूप से आपकी टिप्पणियों के लिए उपयोग करने का प्रारूपण आपके विकास के वातावरण (दृश्य स्टूडियो, ग्रहण के तहत जावाडॉक, ...) पर निर्भर हो सकता है।

जहां तक ​​एससीई का सवाल है, मेरा मानना ​​है कि इससे आपका मतलब निम्नलिखित है:

bool b1;
b1 = somecomplicated_function(); // let me explain what this function does
bool b2 = false;
if (!b1) {                       // SCE : if first function call is already true,
                                 // no need to spend resources executing second function.
  b2 = someother_function();     // this function does something else
}

if (b1 || b2) {
...
}

-7

यदि आप किसी कंपनी में काम करते हैं तो पठनीयता आवश्यक है और आपका कोड किसी और द्वारा पढ़ा जाएगा। यदि आप स्वयं के लिए एक कार्यक्रम लिखते हैं, तो यह आपके ऊपर है कि क्या आप समझदार कोड के लिए प्रदर्शन का त्याग करना चाहते हैं।


23
यह ध्यान में रखते हुए कि "आप छह महीने के समय में" निश्चित रूप से "कोई और" हैं, और "आप कल" कभी-कभी हो सकते हैं। मैं प्रदर्शन के लिए पठनीयता का त्याग कभी नहीं करूंगा जब तक कि मेरे पास कुछ ठोस सबूत नहीं हैं कि प्रदर्शन समस्या थी।
मार्टिन बोनर
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.