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

From Vigyanwiki

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

नेस्टेड फलन का उपयोग संरचित प्रोग्रामिंग के कई दृष्टिकोणों में किया जाता है, जिनमें प्रारंभिक फलन भी सम्मिलित हैं, जैसे कि 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 में भी दिखाई देता है, (जैसा FE का भाग है ) जबकि 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);
}

अन्य उदाहरण सी++11 लैम्ब्डा एक्सप्रेशन सिंटैक्स का उपयोग करके होरे विभाजन आधारित क्विकॉर्ट का निम्नलिखित कार्यान्वयन है:

उद्देश्य

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

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

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

अन्य उपयोग

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

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

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

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

विकल्प

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

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

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

भाषाएँ

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

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

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

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

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

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

कार्यान्वयन

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

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

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

कोई भी गैर-स्थानीय वस्तु, मशीन स्टैक पर कॉल स्टैक में एक्सस-लिंक के माध्यम से पहुंचा जाता है। कॉल करने वाला, सी, कॉल से पूर्व ही p के तत्काल लेक्सिकल इनकैप्सुलेशन, (p) के नवीनतम सक्रियण के लिए सीधा लिंक दबाकर, कॉल की गई प्रक्रिया, p की सहायता करता है। p तब लिंक की निश्चित संख्या (पी.सघन -एक्स.सघन) (सामान्य रूप से अल्प संख्या) का पालन करके निश्चित एक्स के लिए सही सक्रियण शोधित कर सकता है।
कॉल करने वाला (स्वयं) सी.डेप्थ - पी.डेप्थ + 1 पूर्व लिंक का अनुसरण करके यह सीधा लिंक बनाता है, जो (p) के नवीनतम सक्रियण तक ले जाता है, एवं तत्पश्चात अस्थायी रूप से उस सक्रियण के सीधे लिंक के साथ इन्हें बना देता है; लिंक पश्चात में 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.


बाहरी संबंध