Skip to content

पोस्ट

स्विच स्टेटमेंट के लिए केस की जांच

6 दिसंबर 2015 • 11 मिनट पढ़ना

स्विच स्टेटमेंट के लिए केस की जांच

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

1952 में, स्टीफन क्लीन ने अपने पेपर Introduction to Metamathematics में स्विच स्टेटमेंट की कल्पना की। पहला उल्लेखनीय कार्यान्वयन 1958 में ALGOL 58 में था। बाद में, स्विच स्टेटमेंट को अमिट C प्रोग्रामिंग भाषा में शामिल किया गया, जिसने, जैसा कि हम जानते हैं, अधिकांश आधुनिक प्रोग्रामिंग भाषाओं को प्रभावित किया है।

वर्तमान समय में आगे बढ़ते हुए, लगभग हर भाषा में एक स्विच स्टेटमेंट है। हालांकि, कुछ भाषाओं ने स्विच स्टेटमेंट को छोड़ दिया है। सबसे उल्लेखनीय Smalltalk है।

इसने मेरी जिज्ञासा को जगाया, स्विच स्टेटमेंट को Smalltalk से क्यों बाहर रखा गया?

Andy Bower, Dolphin Smalltalk के पीछे के निर्माताओं/समर्थकों में से एक, ने अपने विचार साझा किए कि Smalltalk ने स्विच स्टेटमेंट को क्यों बाहर रखा:

जब मैं पहली बार C++ से Smalltalk में आया, तो मैं समझ नहीं सका कि एक कथित पूर्ण भाषा स्विच/केस कंस्ट्रक्ट का समर्थन कैसे नहीं करती। आखिरकार जब मैं पहली बार BASIC से “संरचित प्रोग्रामिंग” में चला गया तो मुझे लगा कि स्विच सबसे अच्छी चीजों में से एक है। हालांकि, क्योंकि Smalltalk ने स्विच का समर्थन नहीं किया, मुझे इस कमी को दूर करने के तरीके को खोजना और समझना था। सही उत्तर, निश्चित रूप से, बहुरूपता का उपयोग करना है और वस्तुओं को स्वयं सही कोड में भेजना है। फिर मुझे एहसास हुआ कि यह एक “कमी” बिल्कुल नहीं थी, बल्कि Smalltalk मुझे C++ में जो आदी हो गया था उससे कहीं अधिक बेहतर OOP डिजाइन में मजबूर कर रहा था। अगर एक स्विच स्टेटमेंट उपलब्ध होता तो मुझे इसे सीखने में बहुत अधिक समय लगता या, बदतर, मैं अभी भी Smalltalk में C++/Java छद्म-वस्तु शैली में प्रोग्रामिंग कर रहा हो सकता हूं।
मैं तर्क दूंगा कि सामान्य OOP में स्विच स्टेटमेंट की कोई वास्तविक आवश्यकता नहीं है। कभी-कभी, एक गैर-OOP दुनिया (जैसे WM_XXXX Windows संदेशों को प्राप्त करना और भेजना जो वस्तुएं नहीं बल्कि केवल पूर्णांक हैं) के साथ इंटरफेस करते समय, एक स्विच स्टेटमेंट उपयोगी होगा। इन स्थितियों में, विकल्प हैं (जैसे एक डिक्शनरी से भेजना) और वे कितनी बार दिखाई देते हैं यह अतिरिक्त सिंटैक्स के समावेश को वारंट नहीं करता है।

क्या Andy सही था? क्या हम स्विच स्टेटमेंट के बिना बेहतर हैं? क्या अन्य भाषाएं भी स्विच स्टेटमेंट को बाहर करने से लाभान्वित होंगी?

इस प्रश्न पर प्रकाश डालने के लिए, मैंने एक स्विच स्टेटमेंट, एक डिक्शनरी, और बहुरूपता के बीच एक तुलना तैयार की है। चलिए इसे एक स्मैकडाउन कहते हैं। सबसे अच्छा कार्यान्वयन जीते!

प्रत्येक कार्यान्वयन में एक विधि है जो एक पैरामीटर लेती है, एक पूर्णांक, और एक स्ट्रिंग लौटाती है। हम साइक्लोमैटिक जटिलता और रखरखाव सूचकांक का उपयोग करके प्रत्येक कार्यान्वयन की जांच करेंगे। फिर हम तीनों कार्यान्वयन का एक समग्र दृष्टिकोण लेंगे।

कोड।

स्विच स्टेटमेंट

रखरखाव सूचकांक72
साइक्लोमैटिक जटिलता6
    public class SwitchWithFourCases
    {
        public string SwitchStatment(int color)
        {
            var colorString = "Red";

            switch (color)
            {
                case 1:
                    colorString = "Green";
                    break;

                case 2:
                    colorString = "Blue";
                    break;

                case 3:
                    colorString = "Violet";
                    break;

                case 4:
                    colorString = "Orange";
                    break;

            }

            return colorString;
        }
    }

डिक्शनरी

रखरखाव सूचकांक73
साइक्लोमैटिक जटिलता3
public class DictionaryWithFourItems
{ 
    public string Dictionary(int color)
    {
        var colorString = "Red";
        var colors = new Dictionary<int, string> {{1, "Green"}, {2, "Blue"}, {3, "Violet"}, {4, "Orange"}};
        var containsKey = colors.ContainsKey(color);
        if (containsKey)
        {
            colorString = colors[color];
        }

        return colorString;
    }
}

बहुरूपता

कुल रखरखाव सूचकांक94
कुल साइक्लोमैटिक जटिलता15

इंटरफेस

रखरखाव सूचकांक100
साइक्लोमैटिक जटिलता1
public interface IColor
{
    string ColorName { get; }
}

फैक्ट्री

रखरखाव सूचकांक76
साइक्लोमैटिक जटिलता4
public class ColorFactory
{
    public string GetColor(int color)
    {
        IColor defaultColor = new RedColor();
        var colors = GetColors();
        var containsKey = colors.ContainsKey(color);
        if (containsKey)
        {
            var c = colors[color];
            return c.ColorName;
        }

        return defaultColor.ColorName;
    }

    private static IDictionary<int, IColor> GetColors()
    {
        return new Dictionary<int, IColor>
        {
            {1, new GreenColor()}, 
            {2, new BlueColor()}, 
            {3, new VioletColor()}, 
            {4, new OrangeColor()}, 
            {5, new MagentaColor()}
        };
    }
}

कार्यान्वयन

रखरखाव सूचकांक97
साइक्लोमैटिक जटिलता2
public class BlueColor : IColor
{
    public string ColorName => "Blue";
}

public class RedColor : IColor
{
    public string ColorName => "Red";
}

public class GreenColor : IColor
{
    public string ColorName => "Green";
}

public class MagentaColor : IColor
{
    public string ColorName => "Magenta";
}

public class VioletColor : IColor
{
    public string ColorName => "Violet";
}

परिणाम

इससे पहले कि मैं परिणामों में गोता लगाऊं, आइए साइक्लोमैटिक जटिलता और रखरखाव सूचकांक को परिभाषित करें:

  • साइक्लोमैटिक जटिलता तर्क शाखा का माप है। संख्या जितनी कम होगी, उतना बेहतर होगा।
  • रखरखाव सूचकांक कोड की रखरखाव क्षमता को मापता है। यह 0 और 100 के बीच एक पैमाने पर है। संख्या जितनी अधिक होगी, उतना बेहतर होगा।
साइक्लोमैटिक जटिलतारखरखाव सूचकांक
स्विच स्टेटमेंट672
डिक्शनरी373
बहुरूपता1594

हम पहले साइक्लोमैटिक जटिलता की जांच करेंगे।

साइक्लोमैटिक जटिलता के परिणाम सीधे हैं। डिक्शनरी कार्यान्वयन सबसे सरल है। क्या इसका मतलब यह है कि यह सर्वोत्तम समाधान है? नहीं, जैसा कि हम रखरखाव सूचकांक का मूल्यांकन करते समय देखेंगे।

अधिकांश लोग मेरी तरह सोचते हैं, सबसे कम साइक्लोमैटिक जटिलता वाला कार्यान्वयन सबसे अधिक रखरखाव योग्य है — यह और कैसे हो सकता है?

हमारे परिदृश्य में, सबसे कम साइक्लोमैटिक जटिलता वाला कार्यान्वयन सबसे अधिक रखरखाव योग्य नहीं है। वास्तव में हमारे परिदृश्य में, यह विपरीत है। सबसे जटिल कार्यान्वयन सबसे अधिक रखरखाव योग्य है! दिमाग उड़ गया!

यदि आप याद करते हैं, तो रखरखाव सूचकांक स्कोर जितना अधिक होगा, उतना बेहतर होगा। मामले को संक्षेप में कहें तो, बहुरूपता का सर्वोत्तम रखरखाव सूचकांक स्कोर है — लेकिन इसमें सबसे अधिक साइक्लोमैटिक जटिलता भी है। क्या दे रहे हैं? यह सही नहीं लगता।

सबसे जटिल कार्यान्वयन सबसे अधिक रखरखाव योग्य क्यों है? इसका उत्तर देने के लिए, हमें रखरखाव सूचकांक को समझना चाहिए।

रखरखाव सूचकांक में 4 मेट्रिक्स होते हैं: साइक्लोमैटिक जटिलता, कोड की पंक्तियां, टिप्पणियों की संख्या और Halstead वॉल्यूम। पहली तीन मेट्रिक्स अपेक्षाकृत अच्छी तरह से ज्ञात हैं, लेकिन अंतिम, Halstead Volume, अपेक्षाकृत अज्ञात है। साइक्लोमैटिक जटिलता की तरह, Halstead Volume उद्देश्यपूर्वक कोड जटिलता को मापने का प्रयास करता है।

सरल शब्दों में, Halstead Volume कोड में गतिशील भागों (चर, सिस्टम कॉल, अंकगणित, कोडिंग कंस्ट्रक्ट, आदि) की संख्या को मापता है। गतिशील भागों की संख्या जितनी अधिक होगी, जटिलता उतनी अधिक होगी। गतिशील भागों की संख्या जितनी कम होगी, जटिलता उतनी कम होगी। यह बताता है कि बहुरूपी कार्यान्वयन रखरखाव सूचकांक पर उच्च स्कोर क्यों करता है; कक्षाओं में कम या कोई गतिशील भाग नहीं हैं। Halstead Volume को देखने का एक और तरीका यह है कि यह “गतिशील भागों” घनत्व को मापता है।

सॉफ्टवेयर क्या है, अगर यह बदलने के लिए नहीं है? वास्तविक दुनिया को प्रतिबिंबित करने के लिए, हम परिवर्तन ला रहे हैं। मैंने प्रत्येक कार्यान्वयन में एक नया रंग जोड़ा है।

नीचे संशोधित परिणाम दिए गए हैं।

साइक्लोमैटिक जटिलतारखरखाव सूचकांक
स्विच स्टेटमेंट770
डिक्शनरी373
बहुरूपता1795

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

रखरखाव सूचकांक की ओर ध्यान मोड़ते हुए, केवल एक, स्विच स्टेटमेंट, रखरखाव में घट गया। बहुरूपता का रखरखाव स्कोर में सुधार हुआ और फिर भी जटिलता भी बढ़ी (हम इसे घटते हुए देखना पसंद करेंगे)। जैसा कि मैंने ऊपर उल्लेख किया है, यह प्रतिकूल है।

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

Jem Finch Google से स्विच स्टेटमेंट की कमियों पर अपने विचार साझा किए:

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

2. बहुरूपी विधि कार्यान्वयन सही जगह पर लौटने की गारंटी दी जाती है, यह मानते हुए कि वे समाप्त हो जाते हैं। C/C++/Java जैसी फॉल थ्रू भाषा में स्विच स्टेटमेंट को यह सुनिश्चित करने के लिए एक त्रुटि-प्रवण “ब्रेक” स्टेटमेंट की आवश्यकता होती है कि वे स्विच के बाद स्टेटमेंट पर लौटें न कि अगले केस ब्लॉक पर।

3. बहुरूपी विधि कार्यान्वयन का अस्तित्व कंपाइलर द्वारा लागू किया जा सकता है, जो प्रोग्राम को संकलित करने से इनकार कर देगा यदि बहुरूपी विधि कार्यान्वयन गायब है। स्विच स्टेटमेंट ऐसी कोई व्यापकता जांच प्रदान नहीं करते हैं।

4. बहुरूपी विधि प्रेषण अन्य स्रोत कोड तक पहुंच (या पुनः संकलन) के बिना विस्तार योग्य है। स्विच स्टेटमेंट में एक और केस जोड़ने के लिए मूल प्रेषण कोड तक पहुंच की आवश्यकता होती है, न केवल एक जगह में बल्कि हर जगह जहां प्रासंगिक enum को स्विच किया जा रहा है।

5. … आप स्विचिंग उपकरण से स्वतंत्र बहुरूपी विधियों का परीक्षण कर सकते हैं। अधिकांश फ़ंक्शन जो लेखक द्वारा दिए गए उदाहरण की तरह स्विच करते हैं, उनमें अन्य कोड होगा जिसे अलग से परीक्षण नहीं किया जा सकता; आभासी विधि कॉल, दूसरी ओर, कर सकते हैं।

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

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

तीन स्विच स्टेटमेंट अनुकूलन हो सकते हैं:

  1. If-elseif स्टेटमेंट – जब एक स्विच स्टेटमेंट में कम संख्या में केस या विरल केस (गैर-वृद्धिशील मान, जैसे 10, 250, 1000) होते हैं तो इसे एक if-elseif स्टेटमेंट में परिवर्तित किया जाता है।
  2. जंप टेबल – आसन्न केस (1, 2, 3, 4, 5) के बड़े सेट में कंपाइलर स्विच स्टेटमेंट को जंप टेबल में परिवर्तित करता है। जंप टेबल अनिवार्य रूप से एक हैशटेबल है जिसमें मेमोरी में फ़ंक्शन के लिए एक पॉइंटर (गोटो स्टेटमेंट के बारे में सोचें) है।
  3. बाइनरी सर्च – विरल केस के बड़े सेट के लिए कंपाइलर केस को जल्दी से पहचानने के लिए एक बाइनरी सर्च को लागू कर सकता है, जैसे डेटाबेस में एक इंडेक्स कैसे काम करता है। असाधारण मामलों में जहां केस विरल और आसन्न केस की एक बड़ी संख्या है, कंपाइलर तीनों अनुकूलन का एक संयोजन उपयोग करेगा।

सारांश

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

वैकल्पिक समकक्ष कार्यान्वयन, डिक्शनरी, और बहुरूपता की तुलना में, स्विच स्टेटमेंट अच्छी तरह से नहीं निकला।

स्विच स्टेटमेंट यहां रहने के लिए है, लेकिन जैसा कि हमारी तुलना ने दिखाया है, स्विच स्टेटमेंट के बेहतर विकल्प हैं।

कार्यान्वयन Github पर उपलब्ध हैं।

लेखक: Chuck Conway एक AI इंजीनियर हैं जिनके पास सॉफ्टवेयर इंजीनियरिंग का लगभग 30 साल का अनुभव है। वह व्यावहारिक AI सिस्टम बनाते हैं—कंटेंट पाइपलाइन, इंफ्रास्ट्रक्चर एजेंट, और ऐसे टूल जो वास्तविक समस्याओं को हल करते हैं—और अपनी सीख को साझा करते हैं। सोशल मीडिया पर उनसे जुड़ें: X (@chuckconway) या YouTube और SubStack पर उनसे मिलें।

↑ शीर्ष पर वापस जाएं

आपको यह भी पसंद आ सकता है