Кіріспе

Функция ішінде анықталған атаулы функция. Компьютерлік бағдарламалауда, ішкі функция (немесе ішкі процедура немесе кіші бағдарлама) – басқа, қоршау блок ішінде анықталған және қоршау блок шегінде лексикалық түрде қолданылатын, яғни ол қоршау блок ішінде ғана атаумен шақырылуы мүмкін және сыртқы блоктарда, соның ішінде сыртқы функцияларда жарияланған идентификаторларды пайдалана алады. Қоршау блок әдетте, бірақ міндетті емес, басқа функция болады. Ішкі функцияларды бағдарламалау тілінің қолдауы әртүрлі. Құрылымдық бағдарламалау тілдеріне қатысты, ол ALGOL, Simula 67 және Pascal сияқты кейбір ескірген тілдерде және кеңінен қолданылатын JavaScript-те қолдау табады. Ол көбінесе динамикалық және функционалдық тілдерде қолдауға ие. Дегенмен, ол стандартты C және C++ сияқты кейбір кең таралған тілдерде қолдауға ие емес. Басқа бағдарламалау технологиялары да ұқсас мүмкіндіктер ұсынады. Мысалы, lambda функциясы да функцияның ішінде (сондай-ақ басқа жерде) функцияны анықтауға мүмкіндік береді және ұқсас деректерді жасыру мен капсулалауға мүмкіндік береді. Lambda функциясы атаусыз (анонимді) болғандықтан, оны атаумен шақыруға болмайды және көріну қасиеті жоқ.

Атрибуттары

Ұялы функцияның қолданыс аймағы – оны қамтитын блок, функция блогы немесе функция денесіндегі блок. Ол өзінің қамтитын блогынан тыс жерде көрінбейді (атымен шақыру мүмкін емес). Ұялы функция кез келген жоғарыдағы блокта жарияланған идентификаторларды (яғни функциялардың, айнымалылардың, типтердің, сыныптардың атауларын) пайдалана алады, бірақ егер олар бірдей атаулары бар ішкі жариялаулармен жасырылмаса. Ұялы функцияны ұялы функцияның ішінде рекурсивті түрде жариялауға болады, бұл терең ұялы құрылымды қалыптастырады. Терең ұяланған функция барлық жоғарыдағы блоктарында, соның ішінде жоғарыдағы функцияларда жарияланған идентификаторларға қол жеткізе алады. Ұялы функциялар кейбір жағдайларда жабылудың (closure) құрылуына әкелуі мүмкін. Егер ұялы функцияның қоршау функциясынан шығуы мүмкін болса, мысалы, егер функциялар бірінші дәрежелі объектілер болса және ұялы функция басқа функцияға жіберілсе немесе қоршау функциясынан қайтарылса, онда жабылу құрылады және осы функцияға шақырулар бастапқы функцияның ортасына қол жеткізе алады. Негізгі қоршау функциясының стегі соңғы сілтеме жасайтын жабылу жойылғанға дейін сақталуы керек, сондықтан жабылуларда сілтемеленген жергілікті емес автоматты айнымалыларды жабылу блогының өмір сүру мерзімінен кейін де сақтауға рұқсат беретін тілдерде стекке орналастыруға болмайды. Бұл funarg проблемасы деп аталады және ол кейбір қарапайым тілдерде ұялы функциялардың іске асырылмауының басты себебі, себебі ол кодты жасау және талдауды күрделендіреді, әсіресе функциялар әртүрлі деңгейлерде ұяланғанда және олардың ортасының әртүрлі бөліктерін бөліседі.

Құны

Гнестелген функция технологиясы бағдарламашыға ақпаратты жасыру, капсулалау және жіктеу сияқты пайдалы қасиеттері бар бастапқы кодты жазуға мүмкіндік береді. Бағдарламашы бір міндетті, тек сол міндеттің контекстінде ғана мағынасы бар кішігірім міндеттерге бөле алады, соның салдарынан кішігірім міндеттерге арналған функциялар оларды пайдалануға арналмаған шақырушылардан жасырылады. Блоктық ауқым функцияларға қоршаған блоктардың күйін (қоса, қоршаған функцияларды) параметрлерді жібермей немесе жаһандық айнымалыларды қолданбай бөлісуге мүмкіндік береді.

Көмекші

Ұялы функция көбінесе көмекші функция немесе рекурсивті функция болып жұмыс істейді (жоғарыда келтірілген жылдам сұрыптау мысалындағыдай).

Бақылау ағыны

Ұялы функциялар қайтару операторын пайдалану арқылы құрылымдалмаған басқару ағынына қолданылуы мүмкін, бұл осы тілдің басқа кіріктірілген мүмкіндіктеріне қарағанда басқаруды дәлдеуге мүмкіндік береді. Мысалы, егер тоқтату (break) операторы қолжетімді болмаса, for циклін ертерек тоқтатуға, ал көп деңгейлі тоқтату немесе ерекше жағдайлар (exceptions) болмаса, ұялы for циклін ертерек тоқтатуға болады.

Жоғары деңгейдегі функциялар

Кейбір тілдерде сыртқы функциядан параметрлер жиынтығына қол жеткізетін, яғни жабылу (closure) құруға және сол функцияны сыртқы функцияның қайтарым мәні ретінде пайдалануға болады. Осылайша, функцияны белгілі бір міндетті орындау үшін, оған қосымша параметрлер бермей немесе аздаған параметрлермен қайтаруға болады, бұл өнімділікті едәуір арттыруы мүмкін.

Функционалдық тілдер

Функционалдық бағдарламалау тілдерінің көпшілігінде, мысалы Scheme, ұялы функциялар алгоритмдерді ішінде циклдар бар күйінде жүзеге асырудың кең таралған тәсілі болып табылады. Жаңадан (құйрық) рекурсивті ішкі функция жасалады, ол алгоритмнің негізгі циклы ретінде жұмыс істейді, ал сыртқы функция тек бір рет орындалуы тиіс бастапқы әрекеттерді атқарады. Күрделірек жағдайларда бірнеше өзара рекурсивті функциялар ішкі функциялар ретінде құрылуы мүмкін.

Баламалар

Ұялы функциялар арқылы алынатын бағдарламалау нәтижелеріне ұқсас нәтижелерге жету үшін әртүрлі балама техникаларды қолдануға болады.

Модульділік

Жалпыға ортақ балама – тілдің модульдік технологиясын пайдалану. Кейбір функциялар модульден тыс қолдану үшін ашыққа шығарылады, ал кейбіреулері модуль ішінде ғана көрінеді. C тілінде бұл функциялар мен айнымалыларды файлдан тыс кодтан жасыру үшін "static" деп жариялау арқылы іске асырылуы мүмкін. Бұл деректерді жасыруға, инкапсуляциялауға және бөлуге мүмкіндік береді, бірақ бұл ұялы функциялармен салыстырғанда басқа деңгейдегі бөлшектілікпен жүзеге асырылады. Бұл модульдік бір деңгейден артық ұялауды қолдамайды. Объектіге бағытталған тілдерде сынып әдетте функциялар мен күйді сыныпты пайдаланушылардан жасыруға мүмкіндік беретін, бірақ сыныптың ішінде қолжетімді болатын кеңістік қамтамасыз етеді. Кейбір тілдерде сыныптарды ұялатуға болады.

Іске асыру

Ұялы функцияларды іске асыру көрінетіннен күрделірек болуы мүмкін, себебі жергілікті емес айнымалыларды пайдаланатын ұялы функцияға сілтеме жасау жабылу (closure) құрайды. Осы себепті, C, C++ немесе Java сияқты кейбір тілдерде ұялы функциялар қолдау көрсетілмейді, өйткені бұл компиляторларды жасауды қиындатады. Дегенмен, кейбір компиляторлар оларды компиляторға тән кеңейтім ретінде қолдайды. Мұның белгілі бір мысалы – C тілінің GNU C нұсқасы, ол Pascal, Ada және Modula сияқты тілдерге арналған компиляторлармен кодты бөліседі.

Функциялар мәндер ретінде

Лексикалық ауқымы бар жергілікті функцияларды нәтиже ретінде беру үшін, тілдің орындалу коды функцияның өзінің қоршау функциясының ішінде көретін ортасын (деректерді) автоматты түрде тапсыруы керек, сонда ол қоршау функциясының ағымдағы жұмысы аяқталғаннан кейін де қолжетімді болады. Бұл ортаны хронологиялық орындалу стегінен бөлек жад аймағында сақтау қажет, ал бұл өз кезегінде еркін динамикалық жадты бөлуді талап етеді. Сондықтан көптеген ескі Алгол негізделген тілдер (немесе олардың диалектілері) жергілікті емес айнымалыларға қол жеткізетін жергілікті функцияларды қайтару мәні ретінде беруге рұқсат бермейді, тіпті функцияларды қайтару мәні ретінде мүлдем рұқсат етпейді, бірақ мұндай функцияларды аргумент ретінде беруге болады.

Орындалмайтын стектер

GCC-нің ішкі функцияларды (nested functions) іске асыруы орындалмайтын стектердің (NX стектер) жоғалуына себеп болады. Бұл іске асыру орындалу кезінде машина стегіне орналастырылған секіру командасы арқылы ішкі функцияларды шақырады. Бұл стектің орындалатын болуын талап етеді. Сондықтан GCC-де орындалмайтын стектер мен ішкі функциялар өзара сәйкес келмейді. Егер бағдарламаны әзірлеу кезінде ішкі функция қолданылса, онда NX стегі ескертусіз жоғалады, егер GCC жағдай туралы хабарлау үшін ‐Wtrampoline опциясымен шақырылмаса. Қауіпсіз әзірлеу өмірлік циклын (Secure Development Lifecycle) қолданатын бағдарламалық жасақтама көбінесе осы компиляторда NX стектерінің жоғалуына байланысты ішкі функцияларды пайдалануға рұқсат бермейді.