नेस्टेड फ़ंक्शन

From Vigyanwiki
Revision as of 17:58, 4 August 2023 by alpha>Sangeeta

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

नेस्टेड फ़ंक्शंस का उपयोग संरचित प्रोग्रामिंग के कई दृष्टिकोणों में किया जाता है, जिनमें शुरुआती फ़ंक्शन भी शामिल हैं, जैसे कि ALGOL, 67 से और पास्कल (प्रोग्रामिंग भाषा), और कई आधुनिक गतिशील भाषाओं और कार्यात्मक भाषाओं में भी। हालाँकि, वे पारंपरिक रूप से भाषाओं के (मूल रूप से सरल) सी-परिवार में समर्थित नहीं हैं।

प्रभाव

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

नेस्टेड फ़ंक्शंस कुछ स्थितियों (और भाषाओं) में समापन (कंप्यूटर प्रोग्रामिंग) के निर्माण का कारण बन सकते हैं। यदि नेस्टेड फ़ंक्शन के लिए एन्क्लोजिंग फ़ंक्शन के विश्लेषण से बचना संभव है, उदाहरण के लिए यदि फ़ंक्शन प्रथम श्रेणी ऑब्जेक्ट हैं और नेस्टेड फ़ंक्शन को किसी अन्य फ़ंक्शन में पास किया जाता है या एन्क्लोजिंग फ़ंक्शन से वापस लौटाया जाता है, तो क्लोजर बनाया जाता है और इस फ़ंक्शन पर कॉल मूल फ़ंक्शन के वातावरण तक पहुंच सकती है। तुरंत संलग्न करने वाले फ़ंक्शन का फ़्रेम तब तक जीवित रहना चाहिए जब तक कि अंतिम संदर्भ बंद न हो जाए और गैर-स्थानीय चर|क्लोजर में संदर्भित गैर-स्थानीय स्वचालित चर को स्टैक आवंटन नहीं किया जा सकता है। इसे फनर्ग समस्या के रूप में जाना जाता है और यह प्रमुख कारण है कि नेस्टेड फ़ंक्शंस को कुछ सरल भाषाओं में लागू नहीं किया गया क्योंकि यह कोड निर्माण और विश्लेषण को काफी जटिल बनाता है, खासकर जब फ़ंक्शंस को विभिन्न स्तरों पर नेस्ट किया जाता है, उनके पर्यावरण के विभिन्न हिस्सों को साझा किया जाता है।

उदाहरण

पास्कल सिंटैक्स का उपयोग करने वाला उदाहरण (ALGOL, Modula 2, ओबेरॉन (प्रोग्रामिंग भाषा), Ada (प्रोग्रामिंग भाषा), आदि के साथ समान):

function E(x: real): real;
    function F(y: real): real;
    begin
        F := x + y
    end;
begin
    E := F(3) + F(4)
end;

कार्यक्रम F भीतर निहित है E. ध्यान दें कि Eका पैरामीटर x में भी दिखाई देता है F (जैसा F का यह है E) जबकि दोनों x और y बाहर अदृश्य हैं E और F क्रमश।

इसी प्रकार, मानक एमएल में:

fun e (x : real) =
  let
    fun f y = x+y
  in
    f 3 + f 4
  end;

हास्केल (प्रोग्रामिंग भाषा) सिंटैक्स में ही उदाहरण लिखने का तरीका:

e :: Float -> Float
e x = f 3 + f 4 where f y = x + y

जीएनयू कंपाइलर संग्रह सिंटैक्स में भी यही उदाहरण है[1] (सी नेस्टेड फ़ंक्शंस के साथ विस्तारित):

float E(float x)
{
    float F(float y)
    {
        return x + y;
    }
    return F(3) + F(4);
}

जल्दी से सुलझाएं

अधिक यथार्थवादी उदाहरण क्विकसॉर्ट का यह कार्यान्वयन है:[2]

void sort(int *items, int size) {
    void quickSort(int first, int last) {
        void swap(int p, int q) {
            int tmp = items[p];
            items[p] = items[q];
            items[q] = tmp;
        }
        
        int partition() {
            int pivot = items[first], index = first;
            swap(index, last);
            for (int i = first; i < last; i++)
                if (items[i] < pivot)
                    swap(index++, i);
            swap(index, last);
            return index;
        }

        if (first < last) {
            int pivotIndex = partition();
            quickSort(first, pivotIndex - 1);
            quickSort(pivotIndex + 1, last);
        }
    }
    quickSort(0, size - 1);
}

अन्य उदाहरण C++11#Lambda फ़ंक्शंस और अभिव्यक्तियों का उपयोग करके क्विकॉर्ट#होरे विभाजन योजना का निम्नलिखित कार्यान्वयन है|C++11 Anonymous function#C.2B.2B .28चूंकि C.2B.2B11.29: <सिंटैक्सहाइलाइट लैंग=सी++> टेम्पलेट<टाइपनाम RandomAccessIterator> ऑटो सॉर्ट (RandomAccessIterator प्रारंभ, RandomAccessIterator अंत)->शून्य { स्वतः विभाजन = [&]() { //होरे विभाजन योजना ऑटो &पिवोट = *आरंभ; ऑटो फॉरवर्ड कर्सर = आरंभ; ऑटो बैकवर्ड कर्सर = अंत - 1; ऑटो पार्टिशनपोजीशनफाउंड = गलत; ऑटो लोकेटपार्टीशनपोजीशन = [&]() { जबकि (*फॉरवर्डकर्सर <पिवोट) ++फॉरवर्डकर्सर; जबकि (पिवोट < *बैकवर्ड कर्सर) --बैकवर्डकर्सर; यदि (फॉरवर्ड कर्सर >= बैकवर्ड कर्सर) पार्टिशनपोज़िशनफ़ाउंड = सत्य; अन्य स्वैप (*फॉरवर्डकर्सर, *बैकवर्डकर्सर); }; //तुच्छ सहायक कार्य ऑटो MoveOnAndTryAgain = [&]() { ++फॉरवर्डकर्सर; --बैकवर्डकर्सर; }; //वास्तविक विभाजन प्रक्रिया की संक्षिप्त रूपरेखा जबकि (सत्य) { LoatePartitionPosition(); यदि (विभाजनस्थिति मिली) बैकवर्डकर्सर + 1 लौटाएँ; अन्य MoveOnAndTryAgain(); } }; // क्विकसॉर्ट एल्गोरिदम की संक्षिप्त रूपरेखा यदि (प्रारंभ <अंत - 1) { स्वतः विभाजन स्थिति = विभाजन(); सॉर्ट करें (प्रारंभ, विभाजन स्थिति); सॉर्ट करें (विभाजन स्थिति, अंत); } } </सिंटैक्सहाइलाइट>

उद्देश्य

लेक्सिकली नेस्टेड फ़ंक्शन परिभाषाएँ जानकारी छिपाने का रूप हैं और प्रक्रियात्मक कार्यों को उप-कार्यों में विभाजित करने के लिए उपयोगी हैं जो केवल स्थानीय रूप से सार्थक हैं। यह प्रोग्राम के अन्य हिस्सों को उन कार्यों और चरों से अव्यवस्थित होने से बचाता है जो उन हिस्सों से असंबंधित हैं।

इन्हें आम तौर पर आवरण समारोह के रूप में या किसी अन्य फ़ंक्शन के अंदर रिकर्सन (कंप्यूटर विज्ञान) के रूप में उपयोग किया जाता है (जैसा कि ऊपर दिए गए क्विकसॉर्ट उदाहरण में है)। इससे कोड को व्यवस्थित करने का संरचनात्मक लाभ होता है, दायरे को प्रदूषित होने से बचाया जाता है, और कार्यों को आसानी से स्थिति साझा करने की भी अनुमति मिलती है।[3] चूंकि नेस्टेड फ़ंक्शन एनक्लोजिंग फ़ंक्शन के स्थानीय वेरिएबल्स तक पहुंच सकता है, इसलिए नेस्टेड फ़ंक्शन के पैरामीटर्स को पास किए बिना या वैश्विक वेरिएबल का उपयोग किए बिना, कोड को सरल बनाकर राज्य को साझा करना संभव है।

नेस्टेड फ़ंक्शंस वाली भाषाओं में, फ़ंक्शंस में सामान्य रूप से स्थानीय कॉन्स्टेंट (प्रोग्रामिंग), और डेटा प्रकार (स्थानीय चर, पैरामीटर और फ़ंक्शंस के अलावा), [[एनकैप्सुलेशन (लगातार (प्रोग्रामिंग))]] और गहराई के किसी भी स्तर पर ही नेस्टेड तरीके से छिपा हुआ हो सकता है। यह कोड संरचना संभावनाओं को और बढ़ा सकता है।

अन्य उपयोग

प्रवाह नियंत्रित करें

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

उच्च-क्रम के कार्य

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

विकल्प

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

अन्य विकल्प फ़ंक्शन मापदंडों के माध्यम से कार्यों के बीच स्थिति को साझा करना है, प्रतिलिपि की लागत से बचने के लिए अक्सर संदर्भों को तर्क के रूप में पारित करना। सी में इसे आम तौर पर सूचक द्वारा संदर्भ वाली संरचना में कार्यान्वित किया जाता है।[4]इससे फ़ंक्शन कॉल की जटिलता काफी बढ़ जाती है।[3]

PHP और अन्य भाषाओं में अनाम फ़ंक्शन ही मात्र विकल्प है: नेस्टेड फ़ंक्शन को सामान्य फ़ंक्शन के रूप में नहीं, बल्कि संदर्भ द्वारा, स्थानीय चर के रूप में घोषित किया जाता है। अनाम फ़ंक्शन में स्थानीय चर का उपयोग करने के लिए, क्लोजर (कंप्यूटर विज्ञान) का उपयोग करें।

भाषाएँ

लेक्सिकली नेस्टेड फ़ंक्शंस का समर्थन करने वाली प्रसिद्ध भाषाओं में शामिल हैं:

कार्यात्मक भाषाएँ

अधिकांश कार्यात्मक प्रोग्रामिंग भाषाओं में, जैसे कि स्कीम, नेस्टेड फ़ंक्शंस लूप के साथ कलन विधि लागू करने का प्रोग्रामिंग मुहावरा है। सरल (टेल प्रत्यावर्तन ) रिकर्सन आंतरिक फ़ंक्शन बनाया जाता है, जो एल्गोरिदम के मुख्य लूप के रूप में व्यवहार करता है, जबकि बाहरी फ़ंक्शन स्टार्टअप क्रियाएं करता है जिन्हें केवल बार करने की आवश्यकता होती है। अधिक जटिल मामलों में, कई पूँछ प्रत्यावर्तन कार्यों को आंतरिक कार्यों के रूप में बनाया जा सकता है।

प्रत्यक्ष समर्थन के बिना कुछ भाषाएँ

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

  • सी++
    • सी++11 से पहले: कक्षाओं के भीतर कक्षाओं की परिभाषा की अनुमति देता है, स्तर में नेस्टेड फ़ंक्शंस के समान क्लास विधियों का उपयोग करने की क्षमता प्रदान करता है (फ़ंक्शन ऑब्जेक्ट#सी में और सी.2बी.2बी|सी++ में फ़ंक्शन ऑब्जेक्ट देखें)।
    • C++11 के बाद से: उपरोक्त क्विकसॉर्ट उदाहरण के रूप में लैम्ब्डा ्सप्रेशन का उपयोग करके।[9]
  • एफिल (प्रोग्रामिंग भाषा) स्पष्ट रूप से रूटीन के नेस्टिंग की अनुमति नहीं देता है। यह भाषा को सरल बनाए रखने के लिए है, और (मूल्य-रिटर्निंग) फ़ंक्शन के परिणाम को दर्शाने के लिए विशेष चर, परिणाम का उपयोग करने की परंपरा को भी अनुमति देता है।
  • विज़ुअल बेसिक .NET, अनाम तरीकों या लैम्ब्डा ्सप्रेशन का उपयोग करके।
  • जावा (प्रोग्रामिंग भाषा), लैम्ब्डा अभिव्यक्तियों का उपयोग करके[10] (अनाम फ़ंक्शन#जावा देखें) (जावा 8 के बाद से) या वर्कअराउंड के माध्यम से जिसमें अनाम वर्ग होता है जिसमें ही विधि होती है। किसी विधि के लिए स्थानीय घोषित नामित वर्ग का भी उपयोग किया जा सकता है।

कार्यान्वयन

नेस्टेड फ़ंक्शंस का कार्यान्वयन जितना दिखाई दे सकता है उससे कहीं अधिक शामिल हो सकता है, नेस्टेड फ़ंक्शन के संदर्भ के रूप में जो गैर-स्थानीय चर का संदर्भ देता है वह क्लोजर (कंप्यूटर विज्ञान) बनाता है। इस कारण से नेस्टेड फ़ंक्शंस कुछ भाषाओं जैसे C, C++ या Java में समर्थित नहीं हैं क्योंकि इससे कंपाइलर्स को लागू करना अधिक कठिन हो जाता है।[4][11] हालाँकि, कुछ कंपाइलर कंपाइलर विशिष्ट ्सटेंशन के रूप में उनका समर्थन करते हैं। इसका प्रसिद्ध उदाहरण सी का जीएनयू सी कार्यान्वयन है जो पास्कल, एडा और मोडुला जैसी भाषाओं के लिए कंपाइलरों के साथ कोड साझा करता है।

गैर-स्थानीय वस्तुओं तक पहुंच

शाब्दिक रूप से सीमित भाषा में नेस्टेड प्रक्रियाओं को लागू करने के कई तरीके हैं, लेकिन क्लासिक तरीका इस प्रकार है:

कोई भी गैर-स्थानीय वस्तु, ्स, मशीन स्टैक पर कॉल स्टैक में ्सेस-लिंक के माध्यम से पहुंचा जाता है। कॉल करने वाला, सी, कॉल से पहले ही पी के तत्काल लेक्सिकल इनकैप्सुलेशन, (पी) के नवीनतम सक्रियण के लिए सीधा लिंक दबाकर, कॉल की गई प्रक्रिया, पी की सहायता करता है। पी तब लिंक की निश्चित संख्या (पी.गहराई - ्स.गहराई) (सामान्य रूप से छोटी संख्या) का पालन करके निश्चित ्स के लिए सही सक्रियण ढूंढ सकता है।
कॉल करने वाला (स्वयं) सी.डेप्थ - पी.डेप्थ + 1 पुराने लिंक का अनुसरण करके यह सीधा लिंक बनाता है, जो (पी) के नवीनतम सक्रियण तक ले जाता है, और फिर अस्थायी रूप से उस सक्रियण के सीधे लिंक के साथ इन्हें पाट देता है; लिंक बाद में P के साथ गायब हो जाता है, जिससे इसके नीचे के पुराने लिंक फिर से उपयोग में आ सकते हैं।
ध्यान दें कि P दृश्यमान है, और इसलिए इसे C द्वारा बुलाया जा सकता है यदि (P) = C / (C) / ((C)) / आदि।

यह मूल विधि जितनी प्रतीत होती है उससे अधिक तेज़ है, लेकिन फिर भी इसे अक्सर व्यावहारिक आधुनिक कंपाइलरों (कॉल स्टैक#डिस्प्ले या इसी तरह की तकनीकों का उपयोग करके) में अनुकूलित किया जाता है।

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

मूल्यों के रूप में कार्य

शाब्दिक रूप से दायरा गैर-स्थानीय चर वाले स्थानीय कार्यों को परिणाम के रूप में पारित करने के लिए, भाषा रनटाइम कोड को उस वातावरण (डेटा) को भी पारित करना होगा जो फ़ंक्शन अपने इनकैप्सुलेटिंग फ़ंक्शन के अंदर देखता है, ताकि यह तब भी पहुंच योग्य हो जब एन्क्लोजिंग फ़ंक्शन का वर्तमान सक्रियण अब मौजूद नहीं है।[12] इसका मतलब यह है कि पर्यावरण को कालानुक्रमिक रूप से आधारित निष्पादन स्टैक (बाद में पुनः प्राप्त किए गए हिस्सों) की तुलना में किसी अन्य मेमोरी क्षेत्र में संग्रहीत किया जाना चाहिए, जो बदले में, कुछ प्रकार के स्वतंत्र रूप से गतिशील मेमोरी आवंटन का तात्पर्य करता है। इसलिए कई पुरानी अल्गोल आधारित भाषाएं (या उनकी बोलियां) गैर-स्थानीय लोगों तक पहुंचने वाले स्थानीय कार्यों को रिटर्न मान के रूप में पारित करने की अनुमति नहीं देती हैं, या वे फ़ंक्शन को रिटर्न मान के रूप में बिल्कुल भी अनुमति नहीं देते हैं, हालांकि ऐसे कार्यों को तर्क के रूप में पारित करना अभी भी संभव हो सकता है।

नहीं-निष्पादित स्टैक

नेस्टेड फ़ंक्शंस के कम से कम कार्यान्वयन से NX बिट|नो-्ज़ीक्यूट स्टैक (NX स्टैक) का नुकसान होता है। जीसीसी का नेस्टेड फ़ंक्शन कार्यान्वयन रनटाइम पर मशीन स्टैक में डाले गए जंप निर्देश के माध्यम से नेस्टेड फ़ंक्शन को कॉल करता है। इसके लिए स्टैक का निष्पादन योग्य होना आवश्यक है।

जीसीसी के तहत कोई भी निष्पादन स्टैक और नेस्टेड फ़ंक्शन परस्पर अनन्य नहीं हैं। यदि किसी प्रोग्राम के विकास में नेस्टेड फ़ंक्शन का उपयोग किया जाता है, तो एन्स स्टैक चुपचाप खो जाता है। जीसीसी ऑफर करता है -Wtrampoline स्थिति के प्रति सचेत करने की चेतावनी।

सॉफ्टवेयर विकास सुरक्षा का उपयोग करके इंजीनियर किए गए सॉफ़्टवेयर अक्सर NX स्टैक के नुकसान के कारण इस विशेष कंपाइलर (GCC) में नेस्टेड फ़ंक्शंस के उपयोग की अनुमति नहीं देते हैं।[13]

यह भी देखें

संदर्भ

  1. Rothwell, Trevis J. (2011). जीएनयू सी संदर्भ मैनुअल. Free Software Foundation, Inc. p. 63.
  2. Re: Nesting functions- Why?, baavgai, 14 January 2012
  3. 3.0 3.1 Bright 2004.
  4. 4.0 4.1 4.2 "Question 20.24: Why doesn't C have nested functions?, comp.lang.c FAQ
  5. "A tour of the Dart language".
  6. "Functions | Kotlin".
  7. "Nested Methods".
  8. "Nested Functions – Using the GNU Compiler Collection (GCC)". GNU Project. Retrieved 2007-01-06.
  9. "Nested function - Rosetta Code".
  10. "Nested function - Rosetta Code".
  11. answer by Dave Vandervies, Aug 28 '09 at 17:45, to "Why are nested functions not supported by the C standard?"
  12. Such a combination of function code and its environment is sometimes called a closure.
  13. Walton, Jeffrey. "C-Based Toolchain Hardening". The Open Web Application Security Project (OWASP). Retrieved 28 February 2017.


बाहरी संबंध