Динамикалық теру дегеніміз не? Динамикалық теру Php статикалық теру.

Барлығы өте қарапайым. Бұл қонақүй мен жеке пәтердің айырмашылығы сияқты.

Пәтерде тек сонда тіркелгендер тұрады. Егер, айталық, онда Сидоровтар отбасы тұрса, онда Пупкиндер отбасы, біздің өміріміз үшін ол жерде тұра алмайды. Сонымен қатар, бұл пәтерде Петя Сидоров тұра алады, содан кейін Гриша Сидоров сонда көшуі мүмкін (кейде олар тіпті бір уақытта тұруы мүмкін - бұл массив). Бұл статикалық теру.

Сидоровтар отбасы қонақүйде бір уақытта тұра алады. Оларға үнемі тіркелудің қажеті жоқ. Содан кейін олар сол жерден кетеді, ал Pupkins сонда көшеді. Содан кейін Кузнецовтар. Сосын басқа біреу. Бұл динамикалық теру.

Егер бағдарламалауға қайта оралсақ, онда бірінші жағдай (статикалық теру), айталық, C, C++, C#, Java және т.б. тілдерінде кездеседі. Айнымалыға бірінші рет мән тағайындамас бұрын, онда не сақталатынын айту керек: бүтін сандар, өзгермелі нүкте сандары, жолдар және т.б. ( Бұл пәтерде Сидоровтар тұратын болады). Динамикалық теру, керісінше, мұны қажет етпейді. Мәнді тағайындаған кезде, айнымалыға оның түрін бір уақытта тағайындайсыз ( Пупкиндер отбасынан шыққан Вася Пупкин қазір осы қонақүй бөлмесінде тұрады). Бұл PHP, Python және JavaScript сияқты тілдерде кездеседі.

Екі тәсілдің де артықшылықтары мен кемшіліктері бар. Қайсысы жақсы немесе нашар, шешілетін мәселелерге байланысты. Толығырақ, айталық, Википедиядан оқи аласыз.

Статикалық теру арқылы сіз бағдарламаны жазу және алгоритмді әзірлеу кезінде айнымалының түрін нақты білесіз және оны ескеріңіз. анау. егер сіз G айнымалысы төрт байт таңбасыз бүтін сан деп айтқан болсаңыз, онда алгоритмде ол әрқашан төрт байт таңбасыз бүтін болады (егер бір нәрсе болса, онда оны нақты түрлендіру керек немесе аудармашы оны белгілі бір мәнге қалай түрлендіретінін білу керек. жағдаяттардың ауқымы, бірақ, негізінен, егер типтің сәйкессіздігі болса, бұл алгоритмдегі қате және компилятор кем дегенде сізді ескертеді), статикалық жағдайда «Вася ақымақ» жолын нөмірге қоюға болмайды. және айнымалыны қолданар алдында «сан бар ма» анықтау үшін қосымша тексерулер қажет емес, сіз деректердің барлық дұрыстығын бағдарламаға енгізу кезінде немесе алгоритмнің өзі талап ететіндей орындайсыз.

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

  • Динамикалық теру - бағдарламалау тілдерінде және спецификация тілдерінде кеңінен қолданылатын әдіс, онда айнымалы айнымалыны жариялау сәтінде емес, мәнді тағайындау сәтінде түрмен байланыстырылады. Осылайша, бағдарламаның әртүрлі бөліктерінде бір айнымалы әртүрлі типтегі мәндерді қабылдай алады. Динамикалық теру мүмкіндігі бар тілдердің мысалдары Smalltalk, Python, Objective-C, Ruby, PHP, Perl, JavaScript, Lisp, xBase, Erlang, Visual Basic.

    Қарама-қарсы әдіс - статикалық теру.

    Кейбір динамикалық теру нашар тілдерде мәндерді салыстыру мәселесі бар, мысалы, PHP-де «==», «!=» және «===», «!==» салыстыру операторлары бар, мұнда екінші амалдар жұбы мәндерді және айнымалылар түрлерін салыстырады. «===» операциясы келесі өрнекті ақиқат деп санайтын «==»-ден айырмашылығы, толық сәйкестік болған жағдайда ғана ақиқат береді: (1=="1"). Айта кету керек, бұл жалпы динамикалық теру мәселесі емес, нақты бағдарламалау тілдерінде.

Өзара байланысты ұғымдар

Бағдарламалау тілі – компьютерлік бағдарламаларды жазуға арналған ресми тіл. Бағдарламалау тілі программаның сыртқы түрін және оның басқаруымен орындаушы (әдетте компьютер) орындайтын әрекеттерді анықтайтын лексикалық, синтаксистік және семантикалық ережелер жиынтығын анықтайды.

Бағдарламалау тіліндегі синтаксистік қант - бұл синтаксистік мүмкіндіктер, олардың қолданылуы бағдарламаның әрекетіне әсер етпейді, бірақ тілді қолдануды адамдарға ыңғайлы етеді.

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

Кеңейтілген Backus–Naur пішіні (EBNF) – кейбір синтаксистік категориялар басқалары арқылы дәйекті түрде анықталатын синтаксисті анықтауға арналған ресми жүйе. Мәтінмәнсіз формальды грамматиканы сипаттау үшін қолданылады. Никлаус Вирт ұсынған. Бұл Backus-Naur пішіндерінің кеңейтілген өңдеуі, BNF-тен «сыйымды» конструкцияларымен ерекшеленеді, сол экспрессивті қабілетпен оңайлатуға мүмкіндік береді...

Қолданбалы бағдарламалау – бұл декларативті бағдарламалау түрі, онда бағдарлама жазу бір объектіні екінші объектіге жүйелі түрде қолданудан тұрады. Мұндай қолданбаның нәтижесі тағы да қосымшаларға функция ретінде де, аргумент ретінде де қатыса алатын объект және т.б. Бұл бағдарламаның белгілеуін математикалық тұрғыдан анық етеді. Функцияның өрнекпен белгіленуі мән-функцияларды пайдалану мүмкіндігін көрсетеді - функционалдық...

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

Айнымалы – физикалық немесе абстрактілі жүйенің атрибуты, оның әдетте сандық мәнін өзгерте алады. Айнымалы ұғымы математика, ғылым, инженерия және бағдарламалау сияқты салаларда кеңінен қолданылады. Айнымалылардың мысалдары мыналарды қамтиды: ауа температурасы, функция параметрі және т.б.

Тіл білімі мен информатикадағы синтаксистік талдау (немесе талдау, жаргон талдауы ← Ағылшынша талдау) табиғи немесе формалды тілдің лексемаларының (сөздерінің, лексемаларының) сызықтық тізбегін оның формалды грамматикасымен салыстыру процесі. Нәтиже әдетте талдау ағашы (синтаксис ағашы) болып табылады. Әдетте лексикалық талдаумен қатар қолданылады.

Жалпыланған алгебралық деректер түрі (GADT) - алгебралық деректер түрлерінің бірі, оның конструкторлары онымен байланысты типтен басқа мәндерді қайтара алатындығымен сипатталады. Тәуелді типті зерттеушілер арасындағы индуктивті отбасылар бойынша жұмыстардың әсерінен құрастырылған.

Программалаудағы семантика – программалау тілі конструкцияларының мағыналарының формалдануын олардың формальды математикалық модельдерін құру арқылы зерттейтін пән. Мұндай модельдерді құрудың құралдары ретінде әртүрлі құралдарды қолдануға болады, мысалы, математикалық логика, λ-есептер, жиындар теориясы, категориялар теориясы, модельдер теориясы және әмбебап алгебра. Бағдарламалау тілінің семантикасын формализациялау тілді сипаттау, тілдің қасиеттерін анықтау үшін пайдаланылуы мүмкін...

Объектіге бағытталған бағдарламалау (OOP) — бағдарламаны объектілердің жиынтығы ретінде көрсетуге негізделген бағдарламалау әдістемесі, олардың әрқайсысы белгілі бір сыныптың данасы болып табылады және сыныптар мұра иерархиясын құрайды.

Динамикалық айнымалы – бағдарламаның орындалу барысында жедел жадта бос орын бөлінген бағдарламадағы айнымалы. Негізінде, бұл бағдарлама жұмыс істеп тұрған кезде белгілі бір мақсаттар үшін жүйемен бағдарламаға бөлінген жад бөлімі. Оның жаһандық статикалық айнымалыдан айырмашылығы - бағдарлама жұмыс істей бастағанға дейін белгілі бір мақсаттар үшін жүйемен бағдарламаға бөлінген жад бөлігі. Динамикалық айнымалы жадының айнымалы кластарының бірі болып табылады.

Бұл мақала статикалық терілген және динамикалық терілген тілдер арасындағы айырмашылықтарды түсіндіреді, «күшті» және «әлсіз» теру ұғымдарын қарастырады және әртүрлі тілдердегі теру жүйелерінің күші салыстырылады. Соңғы уақытта бағдарламалауда неғұрлым қатаң және күшті теру жүйелеріне қарай айқын қозғалыс болды, сондықтан түрлер мен теру туралы сөйлескенде не туралы айтып жатқанымызды түсіну маңызды.



Түр – мүмкін мәндердің жиынтығы. Бүтін санның 0, 1, 2, 3 және т.б. мәндері болуы мүмкін. Логикалық шын немесе жалған болуы мүмкін. Сіз өзіңіздің түріңізді ойлап таба аласыз, мысалы, мүмкін мәндері «жоғары» және «5» болатын «Жоғары бестік» түрі, басқа ештеңе жоқ. Бұл жол немесе сан емес, бұл жаңа, бөлек түрі.


Статикалық түрде терілген тілдер айнымалылардың түрлерін шектейді: бағдарламалау тілі, мысалы, x бүтін сан екенін білуі мүмкін. Бұл жағдайда бағдарламашыға x = true әрекетін орындауға тыйым салынады, бұл қате код болады. Компилятор оны құрастырудан бас тартады, сондықтан біз тіпті кодты іске қоса алмаймыз. Басқа статикалық түрде терілген тілдің әртүрлі экспрессивті мүмкіндіктері болуы мүмкін және танымал типтегі жүйелердің ешқайсысы біздің HighFive типімізді білдіре алмайды (бірақ көпшілігі басқа, күрделірек идеяларды айта алады).


Динамикалық терілген тілдер мәндерді типтермен белгілейді: тіл 1 бүтін сан, 2 бүтін сан екенін біледі, бірақ х айнымалысы әрқашан бүтін санды қамтитынын біле алмайды.


Тілдің орындалу уақыты бұл белгілерді уақыттың әртүрлі нүктелерінде тексереді. Егер екі мәнді қосуға тырыссақ, ол олардың сандар, жолдар немесе массивтер екенін тексере алады. Содан кейін ол осы мәндерді қосады, оларды бір-біріне жабыстырады немесе түріне байланысты қате жібереді.

Статикалық түрде терілген тілдер

Статикалық тілдер бағдарламаның түрлерін компиляция уақытында, бағдарлама іске қосылмай тұрып тексереді. Түрлері тіл ережелерін бұзатын кез келген бағдарлама дұрыс емес болып саналады. Мысалы, статикалық тілдердің көпшілігі «a» + 1 өрнегін қабылдамайды (C - бұл ережеден ерекшелік). Компилятор «a» - жол және 1 - бүтін сан екенін және сол және оң жақтары бір типте болғанда ғана + жұмыс істейтінін біледі. Сондықтан мәселе бар екенін түсіну үшін оған бағдарламаны іске қосудың қажеті жоқ. Статикалық түрде терілген тілдегі әрбір өрнек кодсыз анықталуы мүмкін белгілі бір түрге жатады.


Көптеген статикалық түрде терілген тілдер тип белгісін қажет етеді. Java функциясы public int add(int x, int y) екі бүтін санды қабылдайды және үшінші бүтін санды қайтарады. Басқа статикалық терілген тілдер түрін автоматты түрде шығаруы мүмкін. Хаскеллдегі бірдей қосу функциясы келесідей көрінеді: x y = x + y қосыңыз. Біз тілге түрлерді айтпаймыз, бірақ ол оларды өзі анықтай алады, өйткені ол тек сандармен жұмыс істейтінін біледі, сондықтан x және y сандар болуы керек, сондықтан қосу функциясы аргумент ретінде екі санды қабылдайды.


Бұл типтік жүйенің «статикалық» сипатын төмендетпейді. Хаскелл типті жүйе статикалық, қатал және күшті болуымен танымал және Хаскелл барлық осы фронттарда Java-дан алда.

Динамикалық терілген тілдер

Динамикалық терілген тілдер типті көрсетуді талап етпейді, бірақ олар оны өздері анықтамайды. Айнымалы типтер іске қосу кезінде нақты мәндерге ие болмайынша белгісіз. Мысалы, Python тіліндегі функция


def f(x, y): қайтару x + y

екі бүтін сандарды қоса алады, жолдарды, тізімдерді біріктіреді және т.б. және біз бағдарламаны іске қоспайынша нақты не болып жатқанын түсіне алмаймыз. Мүмкін f функциясы бір уақытта екі жолмен, ал басқа уақытта екі санмен шақырылады. Бұл жағдайда x және y әр түрлі уақытта әртүрлі типтердің мәндерін қамтиды. Сондықтан динамикалық тілдердегі мәндердің түрі бар деп айтылады, бірақ айнымалылар мен функциялар жоқ. 1 мәні сөзсіз бүтін сан, бірақ x және y кез келген нәрсе болуы мүмкін.

Салыстыру

Көптеген динамикалық тілдер типтер дұрыс пайдаланылмаса, қате жібереді (JavaScript ерекше ерекшелік болып табылады; ол мағынасы жоқ болса да, кез келген өрнек үшін мәнді қайтаруға тырысады). Динамикалық терілген тілдерді пайдаланған кезде, өндіріс ортасында "a" + 1 сияқты қарапайым қате де орын алуы мүмкін. Статикалық тілдер мұндай қателердің алдын алады, бірақ, әрине, алдын алу дәрежесі жүйенің түріне байланысты.


Статикалық және динамикалық тілдер бағдарламаның дұрыстығы туралы түбегейлі әртүрлі идеяларға негізделген. Динамикалық тілде «a» + 1 жарамды бағдарлама: код іске қосылады және орындалу ортасында қате пайда болады. Дегенмен, статикалық терілген тілдердің көпшілігінде «a» + 1 өрнегі бар бағдарлама емес: Ол компиляцияланбайды және іске қосылмайды. Бұл кездейсоқ таңбалар жинағы сияқты қате код!&%^@*&%^@* қате код. Бұл дұрыс және бұрыс деген қосымша ұғымның динамикалық тілдерде баламасы жоқ.

Күшті және әлсіз теру

«Күшті» және «әлсіз» ұғымдары өте екіұшты. Міне, оларды пайдаланудың кейбір мысалдары:

    Кейде «күшті» «статикалық» дегенді білдіреді.
    Бұл қарапайым, бірақ «статикалық» терминін қолданған дұрыс, өйткені оны көпшілік қолданады және түсінеді.

    Кейде «күшті» «жасырын түр түрлендіруді жасамайды» дегенді білдіреді.
    Мысалы, JavaScript «a» + 1 жазуға мүмкіндік береді, оны «әлсіз теру» деп атауға болады. Бірақ барлық дерлік тілдер бүтін сандардан 1 + 1.1 сияқты өзгермелі нүктелі сандарға автоматты түрде түрлендіруге мүмкіндік беретін жасырын түрлендірудің кейбір деңгейін қамтамасыз етеді. Шындығында, адамдардың көпшілігі қолайлы және қабылданбайтын конверсия арасындағы шекараны анықтау үшін «күшті» сөзін пайдаланады. Жалпы қабылданған шекара жоқ, олардың барлығы нақты емес және белгілі бір адамның пікіріне байланысты.

    Кейде «күшті» тілдің қатаң теру ережелерін айналып өту мүмкін емес дегенді білдіреді.

  • Кейде «күшті» есте сақтау үшін қауіпсіз дегенді білдіреді.
    Си - жадқа қауіпті тілдің мысалы. Егер xs төрт саннан тұратын массив болса, онда C xs немесе xs мәндерін жадтан бірден xs артына қайтарып, қуана орындайды.

Тоқтайық. Міне, кейбір тілдер бұл анықтамаларға сәйкес келеді. Көріп отырғаныңыздай, тек Хаскелл барлық жағынан үнемі «күшті». Көптеген тілдер соншалықты анық емес.



(«Жасырын түрлендірулер» бағанындағы «Қашан» дегені күшті және әлсіз деп бөлу қандай түрлендірулерді қолайлы деп санайтынымызға байланысты екенін білдіреді).


Көбінесе «күшті» және «әлсіз» терминдері жоғарыдағы әртүрлі анықтамалардың анық емес комбинациясын білдіреді, ал басқалары мұнда көрсетілмеген. Осы шатасулардың бәрі «күшті» және «әлсіз» сөздерін мағынасыз етеді. Бұл терминдерді пайдаланғыңыз келгенде, нақты нені білдіретінін сипаттаған дұрыс. Мысалы, сіз «саны бар жол қосылғанда JavaScript мәнді қайтарады, бірақ Python қатені қайтарады» деп айтуға болады. Бұл жағдайда біз «күшті» сөзінің бірнеше мағыналары туралы келісімге келуге күш-жігерімізді жұмсамаймыз. Немесе одан да сорақысы: терминологияға байланысты шешілмеген түсініспеушіліктерге тап боламыз.


Көбінесе Интернеттегі «күшті» және «әлсіз» терминдері нақты тұлғалардың бұлыңғыр және нашар анықталған пікірлері болып табылады. Олар тілді «жаман» немесе «жақсы» деп атау үшін қолданылады және бұл пікір техникалық жаргонға айналады.



Күшті теру: маған ұнайтын және ыңғайлы типті жүйе.

Әлсіз теру: мені мазалайтын немесе маған ыңғайлы емес типті жүйе.

Біртіндеп теру

Динамикалық тілдерге статикалық түрлерді қосу мүмкін бе? Кейбір жағдайларда - иә. Басқаларында бұл қиын немесе мүмкін емес. Ең айқын мәселе - динамикалық тілдердің бағалау және басқа ұқсас ерекшеліктері. Python-да 1 + eval("2") әрекетін орындау 3 береді. Бірақ 1 + eval(read_from_the_network()) не береді? Бұл орындау кезінде желіде не бар екеніне байланысты. Егер санды алсақ, онда өрнек дұрыс. Егер бұл жол болса, онда жоқ. Іске қосу алдында білуге ​​мүмкіндік жоқ, сондықтан түрді статикалық түрде талдау мүмкін емес.


Практикадағы қанағаттанарлықсыз шешім - eval() өрнегін Any түріне орнату, ол кейбір объектіге бағытталған бағдарламалау тілдеріндегі Object немесе Go ішіндегі интерфейс() түріне ұқсас: бұл кез келген мәнмен қанағаттандырылатын түр.


Any түрінің мәндері шектеусіз, сондықтан типтік жүйенің бағалау кодымен көмектесу мүмкіндігі жоғалады. Бағалау жүйесі де, типі де бар тілдер бағалау қолданылған кезде тип қауіпсіздігінен бас тартуы керек.


Кейбір тілдерде қосымша немесе біртіндеп теру мүмкіндігі бар: олар әдепкі бойынша динамикалық, бірақ кейбір статикалық аннотацияларды қосуға мүмкіндік береді. Python жақында қосымша түрлерін қосты; TypeScript — қосымша түрлері бар JavaScript жоғарғы жиыны; Flow ескі жақсы JavaScript кодының статикалық талдауын орындайды.


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

Статикалық типтелген кодты құрастыру

Статикалық терілген кодты құрастыру кезінде кез келген компилятордағы сияқты алдымен синтаксис тексеріледі. Содан кейін түрлері тексеріледі. Бұл дегеніміз, статикалық тіл алдымен бір синтаксистік қате туралы шағымдануы мүмкін және оны түзетіп болғаннан кейін 100 теру қатесі туралы шағымдануы мүмкін. Синтаксистік қатені түзету бұл 100 теру қатесін жасамады. Синтаксис түзетілмейінше, компилятордың типтік қателерді анықтау мүмкіндігі болмады.


Статикалық тілдерге арналған компиляторлар әдетте динамикалық тілдерге арналған компиляторларға қарағанда жылдамырақ код жасай алады. Мысалы, егер компилятор қосу функциясы бүтін сандарды қабылдайтынын білсе, онда ол орталық процессордың жергілікті ADD нұсқаулығын пайдалана алады. Динамикалық тіл түрлерге (бүтін сандарды немесе қалқымалы мәндерді қосу, жолдарды біріктіру немесе тізімдерді қосу керек пе?) немесе қате орын алғанын және түрлердің сәйкес келмейтінін шешу қажеттігін таңдай отырып, орындау уақытында түрін тексереді. . Бұл тексерулердің барлығы уақытты алады. Динамикалық тілдер оңтайландыру үшін әртүрлі трюктерді пайдаланады, мысалы, JIT компиляциясы (дәл уақытында), мұнда код барлық қажетті түр ақпараты алынғаннан кейін орындалу уақытында қайта құрастырылады. Дегенмен, ешбір динамикалық тіл Rust сияқты тілдегі ұқыпты жазылған статикалық кодтың жылдамдығына сәйкес келе алмайды.

Статикалық және динамикалық түрлерге арналған аргументтер

Статикалық типті жүйені жақтаушылар типтік жүйесіз қарапайым қателер өндірісте проблемаларға әкелетінін атап көрсетеді. Бұл, әрине, рас. Динамикалық тілді пайдаланған кез келген адам мұны бірінші рет бастан кешірді.


Динамикалық тілдерді жақтаушылар мұндай тілдерде код жазу оңайырақ болатынын айтады. Бұл бағалау коды сияқты біз мезгіл-мезгіл жазатын кодтың кейбір түрлеріне қатысты. Бұл тұрақты жұмыс үшін даулы шешім және бұл жерде «жеңіл» деген түсініксіз сөзді есте сақтау мағынасы бар. Рич Хики «жеңіл» сөзі және оның «қарапайым» сөзімен байланысы туралы айтуда тамаша жұмыс жасады. Бұл есепті көргеннен кейін сіз «оңай» сөзін дұрыс қолдану оңай емес екенін түсінесіз. «Оңайдан» сақ болыңыз.


Статикалық және динамикалық теру жүйелерінің оң және теріс жақтары әлі де аз зерттелген, бірақ олар, әрине, тілге және шешілетін нақты мәселеге байланысты.


JavaScript мағынасыз түрлендіруді білдірсе де жалғастыруға тырысады («a» + 1 нәтижесінде «a1»). Python, керісінше, консервативті болуға тырысады және «a» + 1 жағдайындағы сияқты жиі қателерді қайтарады.


Қауіпсіздік деңгейі әртүрлі әртүрлі тәсілдер бар, бірақ Python және JavaScript екеуі де динамикалық терілген тілдер болып табылады.



Хаскелл алдымен нақты түрлендірусіз бүтін және қалқымалы мәнді қосуға рұқсат бермейді. C және Haskell екеуі де үлкен айырмашылықтарға қарамастан статикалық түрде терілген.


Динамикалық және статикалық тілдердің көптеген нұсқалары бар. «X-ке келгенде статикалық тілдер динамикалық тілдерге қарағанда жақсы» сияқты кез келген жалпы мәлімдеме нонсенс болып табылады. Бұл белгілі бір тілдер жағдайында дұрыс болуы мүмкін, бірақ содан кейін «X-ке келгенде, Haskell Python-ға қарағанда жақсы» деп айту жақсы.

Статикалық теру жүйелерінің әртүрлілігі

Статикалық терілген тілдердің екі әйгілі мысалын қарастырайық: Go және Haskell. Go теру жүйесінде жалпы типтер, басқа түрлерден "параметрлері" бар типтер жоқ. Мысалы, біз кез келген қажетті деректерді сақтай алатын MyList тізімдері үшін өз түрімізді жасай аламыз. Біз MyList бастапқы кодын өзгертпей бүтін сандардың MyList, жолдардың MyList және т.б. жасау мүмкіндігін алғымыз келеді. Компилятор теруді қадағалап отыруы керек: бүтін сандардың MyList тізімі болса және біз оған кездейсоқ жол қоссақ, онда компилятор бағдарламаны қабылдамау керек.


Go қызметі MyList сияқты түрлерді анықтауға рұқсат бермеу үшін арнайы жасалған. Ең дұрысы «бос интерфейстердің» MyList тізімін жасау: MyList нысандарды қамтуы мүмкін, бірақ компилятор олардың түрін білмейді. MyList ішінен нысандарды алған кезде компиляторға олардың түрін айтуымыз керек. Егер біз «Мен жолды алып жатырмын» десек, бірақ шын мәнінде мән сан болса, динамикалық тілдердегідей орындалу қатесі болады.


Go қолданбасында қазіргі статикалық терілген тілдерде (немесе тіпті 1970 жылдардағы кейбір жүйелерде) табылған көптеген басқа мүмкіндіктер жоқ. Go авторларының бұл шешімдерге өз себептері болды, бірақ бұл мәселеге қатысты бөгде адамдардың пікірлері кейде қатал болып көрінуі мүмкін.


Енді өте қуатты типтік жүйесі бар Хаскеллмен салыстырайық. Түрді MyList деп орнатсаңыз, «сандар тізімі» түрі жай MyList Integer болады. Хаскелл тізімге кездейсоқ жолды қосудан сақтайды және тізімдегі элементті жол айнымалысына қоймауымызға көз жеткізеді.


Хаскелл әлдеқайда күрделі идеяларды түрлермен тікелей жеткізе алады. Мысалы, Num a => MyList a «Бірдей сандар түріне жататын мәндер тізімі» дегенді білдіреді. Бұл бүтін сандардың, қалқымалы мәндердің немесе нақты ондықтардың тізімі болуы мүмкін, бірақ ол ешқашан компиляция уақытында тексерілетін жолдардың тізімі болмайды.


Кез келген сан түрімен жұмыс істейтін қосу функциясын жазуға болады. Бұл функцияның түрі Num a => (a -> a -> a) болады. Бұл білдіреді:

  • a кез келген сандық тип болуы мүмкін (Num a =>).
  • Функция a түріндегі екі аргументті қабылдайды және a (a -> a -> a) түрін қайтарады.

Соңғы мысал. Егер функция түрі String -> String болса, ол жолды қабылдайды және жолды қайтарады. Бірақ егер ол String -> IO String болса, онда ол кейбір енгізу/шығару қызметін де орындайды. Бұл дискіге кіру, желіге кіру, терминалдан оқу және т.б. болуы мүмкін.


Егер функцияның түрі болса Жоқ IO, онда біз оның ешқандай енгізу/шығару операцияларын орындамайтынын білеміз. Мысалы, веб-бағдарламада функция дерекқорды оның түріне қарап өзгертетінін білуге ​​болады. Ешбір динамикалық және статикалық тілдер мұны істей алмайды. Бұл ең күшті теру жүйелері бар тілдердің ерекшелігі.


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


Бұл қуатты Go-мен салыстырыңыз, ол MyList-тің қарапайым идеясын айта алмайды, «сандық және бір типтегі екі аргументті қабылдайтын және енгізу/шығару функциясын» айтпағанда.


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


Go және Haskell - бұл әртүрлі тілдер, сондықтан оларды «статикалық тілдердің» бір класына топтау, термин дұрыс қолданылғанына қарамастан, жаңылыстыруы мүмкін. Қауіпсіздіктің практикалық артықшылықтарын салыстыру кезінде Go Хаскеллге қарағанда динамикалық тілдерге жақынырақ.


Екінші жағынан, кейбір динамикалық тілдер кейбір статикалық тілдерге қарағанда қауіпсіз. (Python әдетте C қарағанда әлдеқайда қауіпсіз деп саналады). Статикалық немесе динамикалық тілдерді топтар ретінде жалпылауды қаласаңыз, тілдер арасындағы айырмашылықтардың үлкен санын ұмытпаңыз.

Теру жүйелерінің мүмкіндіктерінің айырмашылығының нақты мысалдары

Неғұрлым қуатты теру жүйелері шектеулерді кішірек деңгейлерде көрсете алады. Міне, кейбір мысалдар, бірақ синтаксис түсініксіз болса, оларға тым көп ілінбеңіз.


Go бағдарламасында «қосу функциясы екі бүтін санды қабылдайды және бүтін санды қайтарады» деп айта аласыз:


func add(x int, y int) int ( қайтару x + y )

Хаскеллде сіз «функция қабылдайды кез келгенсандық түрі және бірдей түрдегі санды қайтарады»:


f:: Сан a => a -> a -> a x y = x + y қосыңыз

Idris-те «функция екі бүтін санды қабылдайды және бүтін санды қайтарады, бірақ бірінші аргумент екінші аргументтен аз болуы керек» деп айта аласыз:


қосу: (x: Nat) -> (y: Nat) -> (автоматты түрде кішірейту: LT x y) -> Nat қосу x y = x + y

Бірінші аргумент екіншісінен үлкен болатын add 2 1 функциясын шақыруға әрекеттенсеңіз, компилятор бағдарламаны қабылдамайды. компиляция уақытында. Бірінші аргумент екіншісінен үлкен болатын программаны жазу мүмкін емес. Тілде мұндай мүмкіндік сирек кездеседі. Көптеген тілдерде бұл тексеру орындалу уақытында орындалады: біз x >= y: rise SomeError() сияқты нәрсені жазамыз.


Жоғарыдағы Idris мысалындағы түрге Haskell баламасы жоқ және Haskell немесе Idris мысалына Go баламасы жоқ. Нәтижесінде Идрис Хаскелл алдын ала алмайтын көптеген қателердің алдын алады, ал Хаскелл Go байқамайтын көптеген қателердің алдын алады. Екі жағдайда да тілді күрделі ету үшін теру жүйесінің қосымша мүмкіндіктері қажет.

Кейбір статикалық тілдердің теру жүйелері

Мұнда қуатты арттыру тәртібі бойынша кейбір тілдердің теру жүйелерінің шамамен тізімі берілген. Бұл тізім сізге жүйелердің күші туралы жалпы түсінік береді, оны абсолютті шындық ретінде қарастырмаңыз. Бір топта жиналған тілдер бір-бірінен мүлдем өзгеше болуы мүмкін. Әрбір теру жүйесінің өзіндік ерекшеліктері бар және олардың көпшілігі өте күрделі.

  • C (1972), Go (2009): Бұл жүйелер жалпы түрлерге қолдаусыз, мүлдем қуатты емес. «Бүтін сандар тізімі», «жолдар тізімі» т.б. білдіретін MyList түрін анықтау мүмкін емес. Оның орнына сіз «белгіленбеген мәндер тізімін» жасауыңыз керек. Бағдарламашы тізімнен жол шығарылған сайын «бұл жолдар тізімі» деп қолмен есеп беруі керек және бұл орындау қатесіне әкелуі мүмкін.
  • Java (1995), C# (2000): Екі тіл де жалпы типтерді қолдайды, сондықтан MyList деп айтуға болады және компилятор білетін және тип ережелерін орындай алатын жолдардың тізімін алыңыз. Тізімдегі элементтер String типті болады және компилятор әдеттегідей компиляция ережелерін мәжбүрлейді, сондықтан орындау уақытындағы қателер ықтималдығы аз.
  • Хаскелл (1990), Rust (2010), Свифт (2014): Бұл тілдердің барлығында жалпы типтерді, алгебралық деректер түрлерін (ADT) және типтік сыныптарды немесе ұқсас нәрсені (сәйкесінше сынып түрлері, белгілер және протоколдар) қоса алғанда, бірнеше кеңейтілген мүмкіндіктер бар. Rust және Swift Хаскеллге қарағанда танымал және оларды ірі ұйымдар алға жылжытады (тиісінше Mozilla және Apple).
  • Агда (2007), Ыдырыс (2011): Бұл тілдер тәуелді типтерді қолдайды, бұл «екі бүтін x және y сандарын қабылдайтын функция, мұндағы y x-тен үлкен» сияқты түрлерді жасауға мүмкіндік береді. Тіпті компиляция кезінде "y x-тен үлкен" шектеуі мәжбүр болады. Орындалған кезде, y еш уақытта не болғанына қарамастан x-тен кем немесе тең болмайды. Жүйенің өте нәзік, бірақ маңызды қасиеттерін осы тілдерде статикалық түрде тексеруге болады. Оларды өте аз бағдарламашылар зерттейді, бірақ бұл тілдер олардың арасында үлкен ынта тудырады.

Күшті теру жүйелеріне қарай нақты қозғалыс бар, әсіресе бар тілдер фактісімен емес, тілдердің танымалдылығымен өлшенеді. Айтарлықтай ерекшелік - бұл Go бағдарламасы, бұл статикалық тілдердің көптеген жақтаушылары оны артқа қарай қадам деп санайтынын түсіндіреді.


Екінші топ (Java және C#) - жетілген және кеңінен қолданылатын негізгі тілдер.


Үшінші топ Mozilla (Rust) және Apple (Swift) үлкен қолдауымен негізгі ағымға кірудің шыңында.


Төртінші топ (Идрис және Агда) негізгі ағымнан алшақ, бірақ уақыт өте келе өзгеруі мүмкін. Үш топтағы тілдер он жыл бұрын негізгі ағымнан алыс еді.

Бұл мақалада динамикалық теруді зұлымдық деп атамау үшін теру туралы білу қажет нәрселердің қажетті минимумы бар, Lisp - типсіз тіл және C қатты терілген тіл.

Толық нұсқада код мысалдарымен, танымал бағдарламалау тілдеріне сілтемелермен және иллюстрациялық суреттермен толықтырылған терудің барлық түрлерінің толық сипаттамасы бар.

Алдымен мақаланың қысқа нұсқасын, ал қаласаңыз толық нұсқасын оқуды ұсынамын.

Қысқа нұсқа

Теру негізінде бағдарламалау тілдері әдетте екі үлкен лагерьге бөлінеді - терілген және типсіз (типсіз). Біріншісіне, мысалы, C, Python, Scala, PHP және Lua кіреді, ал екіншісіне ассемблер тілі, Forth және Brainfuck кіреді.

«Түрсіз теру» өз мәні бойынша штепсель сияқты қарапайым болғандықтан, ол одан әрі басқа түрлерге бөлінбейді. Бірақ терілген тілдер бірнеше қабаттасатын санаттарға бөлінеді:

  • Статикалық/динамикалық теру. Статикалық айнымалылар мен функциялардың соңғы түрлері компиляция уақытында орнатылатындығымен анықталады. Анау. компилятор қай түрдің қайда екеніне 100% сенімді. Динамикалық теруде барлық түрлер бағдарламаның орындалу барысында ашылады.

    Мысалдар:
    Статикалық: C, Java, C#;
    Динамикалық: Python, JavaScript, Ruby.

  • Күшті/әлсіз теру (кейде күшті/әлсіз деп те аталады). Күшті теру тілдің өрнектерде әртүрлі типтерді араластыруға мүмкіндік бермейтіндігімен және автоматты түрде жасырын түрлендірулерді орындамайтынымен ерекшеленеді, мысалы, жолдан жиынды шегеруге болмайды. Әлсіз терілген тілдер дәлдік жоғалуы мүмкін немесе түрлендіру анық емес болса да, көптеген жасырын түрлендірулерді автоматты түрде орындайды.

    Мысалдар:
    Күшті: Java, Python, Haskell, Lisp;
    Әлсіз: C, JavaScript, Visual Basic, PHP.

  • Айқын/жасырын теру. Ашық терілген тілдер жаңа айнымалылардың/функциялардың/олардың аргументтерінің түрі анық көрсетілуі керектігімен ерекшеленеді. Тиісінше, жасырын теру бар тілдер бұл тапсырманы компиляторға/аудармашыға ауыстырады.

    Мысалдар:
    Айқын: C++, D, C#
    Жасырын: PHP, Lua, JavaScript

Сондай-ақ, бұл санаттардың барлығы бір-біріне сәйкес келетінін атап өткен жөн, мысалы, Си тілінде статикалық әлсіз айқын теру, ал Python тілінде динамикалық күшті жасырын теру бар.

Дегенмен, бір уақытта статикалық және динамикалық теру бар тілдер жоқ. Алға қарап, мен осында жатырмын деп айтамын - олар шынымен бар, бірақ бұл туралы кейінірек.

Егжей-тегжейлі нұсқа

Егер қысқа нұсқа сізге жеткіліксіз болса, бұл жақсы. Егжей-тегжейлі жазғаным бекер емес пе? Ең бастысы, барлық пайдалы және қызықты ақпаратты қысқа нұсқаға сыйғызу мүмкін емес еді, ал егжей-тегжейлі ақпарат барлығына тырнақсыз оқу үшін тым ұзақ болуы мүмкін.

Түрсіз теру

Түрі жоқ бағдарламалау тілдерінде барлық нысандар әртүрлі ұзындықтағы биттердің жай тізбегі ретінде қарастырылады.

Түрсіз теру әдетте төмен деңгейлі (ассемблер тілі, Forth) және эзотерикалық (Brainfuck, HQ9, Piet) тілдерге тән. Дегенмен, оның кемшіліктерімен бірге кейбір артықшылықтары да бар.

Артықшылықтары
  • Сізге өте төмен деңгейде жазуға мүмкіндік береді және компилятор/аудармашы кез келген түрді тексеруге кедергі жасамайды. Деректердің кез келген түріне кез келген операцияларды орындауға еркінсіз.
  • Алынған код әдетте тиімдірек болады.
  • Нұсқаулардың ашықтығы. Егер сіз тілді білсеңіз, әдетте бұл немесе басқа кодтың не екеніне күмән жоқ.
Кемшіліктер
  • Күрделілігі. Тізімдер, жолдар немесе құрылымдар сияқты күрделі мәндерді көрсету қажеттілігі жиі туындайды. Бұл қолайсыздықты тудыруы мүмкін.
  • Тексерулердің болмауы. Символдан массивке көрсеткішті алып тастау сияқты кез келген мағынасыз әрекеттер толығымен қалыпты болып саналады, бұл нәзік қателерге толы.
  • Абстракцияның төмен деңгейі. Кез келген күрделі деректер түрімен жұмыс істеу сандармен жұмыс істеуден еш айырмашылығы жоқ, бұл әрине көптеген қиындықтар туғызады.
Күшті типсіз теру?

Иә, бұл бар. Мысалы, ассемблер тілінде (x86/x86-64 архитектурасы үшін, басқаларды білмеймін) rax регистрінен (64 бит) cx регистріне (16 бит) деректерді жүктеп алсаңыз, бағдарламаны құрастыра алмайсыз. .

mov cx, eax ; құрастыру уақытының қатесі

Сонда ассемблер әлі де теріп жүргені белгілі болды ма? Бұл тексерулер жеткіліксіз деп есептеймін. Ал сіздің пікіріңіз, әрине, тек өзіңізге байланысты.

Статикалық және динамикалық теру

Статикалық теруді динамикалық теруден ерекшелендіретін басты нәрсе барлық типті тексеру орындалу уақытында емес, компиляция уақытында орындалады.

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

Оны анықтап көрейік.

Статикалық терудің артықшылықтары
  • Түрді тексеру тек бір рет – компиляция сатысында болады. Бұл санды жолға бөлуге (және қате жіберуге немесе түрлендіруге) тырысып жатқанымызды үнемі анықтаудың қажеті жоқ дегенді білдіреді.
  • Орындау жылдамдығы. Алдыңғы тармақтан статикалық түрде терілген тілдер динамикалық терілгенге қарағанда әрдайым дерлік жылдамырақ екені анық.
  • Кейбір қосымша шарттарда ол құрастыру сатысында әлеуетті қателерді анықтауға мүмкіндік береді.
Динамикалық терудің артықшылықтары
  • Әмбебап жинақтарды жасаудың қарапайымдылығы - барлығының және барлығының үйінділері (мұндай қажеттілік сирек туындайды, бірақ динамикалық теру пайда болған кезде бұл көмектеседі).
  • Жалпыланған алгоритмдерді сипаттаудың ыңғайлылығы (мысалы, бүтін сандар тізімінде ғана емес, нақты сандар тізімінде және тіпті жолдар тізімінде де жұмыс істейтін массивтерді сұрыптау).
  • Үйрену оңай - Динамикалық терілген тілдер әдетте бағдарламалауды бастау үшін өте жақсы.

Жалпыланған программалау

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

Оны қалай шешпекпіз? Оны 3 түрлі тілде шешейік: біреуі динамикалық терумен және екеуі статикалық терумен.

Мен қарапайым іздеу алгоритмдерінің бірін қолданатын боламын - brute force. Функция ізделетін элементті, массивтің (немесе тізімнің) өзін қабылдайды және элементтің индексін қайтарады немесе элемент табылмаса - (-1).

Динамикалық шешім (Python):

Def find(required_element, list): for (index, element) in enumerate(list): if element == required_element: қайтару индексі (-1)

Көріп отырғаныңыздай, бәрі қарапайым және тізімде сандар, тізімдер немесе басқа массивтер болуы мүмкін екендігімен ешқандай проблемалар жоқ. Өте жақсы. Әрі қарай жүрейік - C тілінде бірдей мәселені шешіңіз!

Статикалық шешім (C):

Unsigned int find_int(int required_element, int массив, unsigned int size) (үшін (unsigned int i = 0; i)< size; ++i) if (required_element == array[i]) return i; return (-1); } unsigned int find_float(float required_element, float array, unsigned int size) { for (unsigned int i = 0; i < size; ++i) if (required_element == array[i]) return i; return (-1); } unsigned int find_char(char required_element, char array, unsigned int size) { for (unsigned int i = 0; i < size; ++i) if (required_element == array[i]) return i; return (-1); }

Әрбір функция жеке Python нұсқасына ұқсас, бірақ неге олардың үшеуі бар? Статикалық бағдарламалау шынымен жоғалды ма?

Иә және жоқ. Бірнеше бағдарламалау әдістері бар, олардың біреуін қазір қарастырамыз. Ол жалпы бағдарламалау деп аталады және C++ тілі оны жақсы қолдайды. Жаңа нұсқаны қарастырайық:

Статикалық шешім (жалпы бағдарламалау, C++):

Үлгі unsigned int find(T required_element, std::vektor массив) (үшін (таңбасыз int i = 0; i< array.size(); ++i) if (required_element == array[i]) return i; return (-1); }

Жақсы! Бұл Python нұсқасына қарағанда күрделірек көрінбейді және көп жазуды қажет етпейді. Сонымен қатар, біз мәселені шешу үшін қажет 3 емес, барлық массивтер үшін іске асыруды алдық!

Бұл нұсқа бізге дәл керек сияқты - біз статикалық терудің артықшылықтарын да, динамикалық терудің кейбір артықшылықтарын аламыз.

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

Динамикадағы статика

Сондай-ақ, көптеген статикалық тілдер динамикалық теруге мүмкіндік беретінін атап өткен жөн, мысалы:

  • C# динамикалық псевдотипті қолдайды.
  • F# ? операторы түріндегі синтаксистік қантты қолдайды, оның негізінде динамикалық терудің имитациясын жүзеге асыруға болады.
  • Haskell – динамикалық теру Data.Dynamic модулімен қамтамасыз етілген.
  • Delphi – арнайы Variant түрі арқылы.

Сондай-ақ, кейбір динамикалық терілген тілдер статикалық терудің артықшылығын пайдалануға мүмкіндік береді:

  • Common Lisp - типті мәлімдемелер.
  • Perl - 5.6 нұсқасынан бастап, өте шектеулі.

Күшті және әлсіз теру

Қатты терілген тілдер әртүрлі типтегі нысандарды өрнектерге араластыруға мүмкіндік бермейді және ешқандай автоматты түрлендірулерді орындамайды. Оларды «қатты терілген тілдер» деп те атайды. Бұл үшін ағылшын тіліндегі термин күшті теру.

Әлсіз терілген тілдер, керісінше, бағдарламашыны бір өрнекте әртүрлі типтерді араластыруға итермелейді, ал компилятордың өзі бәрін бір типке дейін қысқартады. Оларды «бос терілген тілдер» деп те атайды. Бұл үшін ағылшын тіліндегі термин әлсіз теру.

Әлсіз теру жиі динамикалық терумен шатастырылады, бұл мүлдем дұрыс емес. Динамикалық терілген тіл әлсіз немесе күшті терілген болуы мүмкін.

Дегенмен, аз адамдар теру қатаңдығына мән береді. Егер тіл статикалық түрде терілген болса, компиляция кезінде көптеген ықтимал қателерді байқауға болады деп жиі айтылады. Олар саған өтірік айтып жатыр!

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

Сонда әлсіз терудің артықшылығы жоқ па? Бұл осылай көрінуі мүмкін, бірақ мен күшті терудің қызу жақтаушысы болғаныма қарамастан, әлсіз терудің де артықшылықтары бар екеніне келісемін.

Олардың қайсысы екенін білгіңіз келе ме?

Күшті терудің артықшылықтары
  • Сенімділік - дұрыс емес әрекеттің орнына сіз ерекше жағдайды немесе жинақтау қатесін аласыз.
  • Жылдамдық - өте қымбат болуы мүмкін жасырын түрлендірулердің орнына күшті теру арқылы оларды анық жазу керек, бұл бағдарламашыны кем дегенде кодтың бұл бөлігі баяу болуы мүмкін екенін білуге ​​мәжбүр етеді.
  • Бағдарламаның қалай жұмыс істейтінін түсіну - тағы да жасырын түрдегі кастингтің орнына, бағдарламашы бәрін өзі жазады, яғни ол жол мен санды салыстыру сиқырмен емес, өздігінен болмайтынын шамамен түсінеді.
  • Белгілілік - түрлендірулерді қолмен жазғанда сіз нені және нені түрлендіретініңізді нақты білесіз. Сондай-ақ, мұндай түрлендірулер дәлдікті жоғалтуға және қате нәтижелерге әкелуі мүмкін екенін әрқашан білетін боласыз.
Әлсіз терудің артықшылықтары
  • Аралас өрнектерді қолданудың ыңғайлылығы (мысалы, бүтін және нақты сандардан).
  • Теруден абстракциялау және тапсырмаға назар аудару.
  • Жазбаның қысқалығы.

Жарайды, біз түсіндік, әлсіз терудің де артықшылықтары бар екен! Әлсіз терудің артықшылықтарын күшті теруге көшіру жолдары бар ма?

Тіпті екеуі бар екен.

Бір мәнді жағдайларда және деректерді жоғалтпай, жасырын түрдегі кастинг

Уау... Өте ұзақ сөз. Оны әрі қарай «шектелген жасырын түрлендіру» деп қысқартуға рұқсат етіңіз, бір мәнді жағдай және деректердің жоғалуы нені білдіреді?

Бір мәнді жағдай – мәні бірден түсінікті болатын түрлендіру немесе операция. Мысалы, екі санды қосу – бір мәнді жағдай. Бірақ санды массивке түрлендіру мүмкін емес (мүмкін бір элементтің массиві жасалуы мүмкін, мүмкін мұндай ұзындықтағы массив әдепкі бойынша элементтермен толтырылады және мүмкін сан жолға, содан кейін массивке түрлендіріледі кейіпкерлер).

Деректерді жоғалту одан да оңай. Егер 3,5 нақты санын бүтін санға түрлендірсек, деректердің бір бөлігін жоғалтамыз (шын мәнінде бұл операция да екіұшты – дөңгелектеу қалай орындалады? Жоғары? Төмен? Бөлшек бөлігін алып тастау?).

Түсініксіз жағдайларда түрлендіру және деректердің жоғалуы бар түрлендіру өте, өте нашар. Бағдарламалауда бұдан жаман ештеңе жоқ.

Маған сенбесеңіз, PL/I тілін оқыңыз немесе оның спецификациясын қараңыз. Онда БАРЛЫҚ деректер түрлері арасында түрлендіру ережелері бар! Бұл жәй тозақ!

Жарайды, шектеулі жасырын түрлендіруді еске түсірейік. Ондай тілдер бар ма? Иә, мысалы Паскаль тілінде бүтін санды нақты санға түрлендіруге болады, бірақ керісінше емес. C#, Groovy және Common Lisp тілдерінде де ұқсас механизмдер бар.

Жарайды, мен күшті тілде әлсіз терудің бірнеше артықшылығын алудың әлі де жолы бар екенін айттым. Иә, ол бар және конструкторлық полиморфизм деп аталады.

Мен оны керемет Хаскелл тілінің мысалы арқылы түсіндіремін.

Полиморфты конструкторлар сандық литералдарды пайдаланған кезде қауіпсіз жасырын түрлендірулер жиі қажет болатынын байқау нәтижесінде пайда болды.

Мысалы, pi + 1 өрнегінде pi + 1.0 немесе pi + float(1) деп жазғыңыз келмейді. Мен жай ғана pi + 1 жазғым келеді!

Және бұл Хаскеллде жасалады, 1 литералдың нақты түрі жоқ болғандықтан. Ол тұтас та, нақты да, күрделі де емес. Бұл жай ғана сан!

Нәтижесінде, қарапайым функцияны жазғанда sum x y , барлық сандарды х-тен у-ға (1-ге өсіммен) көбейткенде, біз бірден бірнеше нұсқаны аламыз - бүтін сандар үшін қосынды, реал үшін қосынды, рационалдар үшін қосынды, күрделі сандар үшін қосынды. және тіпті өзіңіз анықтаған барлық сандық түрлер үшін қосынды.

Әрине, бұл әдіс сандық әріптермен аралас өрнектерді қолданғанда ғана үнемдейді және бұл айсбергтің ұшы ғана.

Осылайша, ең жақсы шешім - күшті және әлсіз теру арасындағы тепе-теңдік деп айта аламыз. Бірақ әлі ешбір тіл тамаша тепе-теңдікке ие емес, сондықтан мен әлсіз терілген тілдерге (мысалы, C, JavaScript, Lua, PHP) емес, қатты терілген тілдерге (мысалы, Haskell, Java, C#, Python) көбірек жүгінемін.

Айқын және жасырын теру

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

Жанама түрде терілген тіл, керісінше, типтерді ұмытып, түрлерді шығару міндетін компиляторға немесе интерпретаторға қалдыруға шақырады. Бұл үшін ағылшын тіліндегі термин жасырын теру.

Бастапқыда сіз жасырын теру динамикалыққа, ал ашық теру статикалыққа тең деп ойлауыңыз мүмкін, бірақ кейінірек бұлай емес екенін көреміз.

Әр түрдің артықшылығы бар ма және тағы да олардың комбинациясы бар ма және екі әдісті де қолдайтын тілдер бар ма?

Ашық терудің артықшылықтары
  • Әрбір функцияның қолтаңбасы болуы (мысалы, int add(int, int)) функцияның не істейтінін анықтауды жеңілдетеді.
  • Бағдарламалаушы белгілі бір айнымалы мәндердің қандай түрін сақтауға болатынын бірден жазады, бұл оны есте сақтау қажеттілігін болдырмайды.
Имплицитті терудің артықшылықтары
  • Стенографиялық белгі - def add(x, y) int add(int x, int y) қарағанда қысқарақ.
  • Өзгерістерге қарсылық. Мысалы, егер функцияда уақытша айнымалы кіріс аргументімен бірдей типте болса, онда анық терілген тілде кіріс аргументінің түрін өзгерткен кезде уақытша айнымалының түрін де өзгерту қажет болады.

Жарайды, екі тәсілдің де оң және теріс жақтары бар екені анық (басқа нәрсені кім күтті?), сондықтан осы екі тәсілді біріктіру жолдарын іздеп көрейік!

Таңдау бойынша анық теру

Әдепкі бойынша жасырын теру және қажет болған жағдайда мәндер түрін көрсету мүмкіндігі бар тілдер бар. Аудармашы өрнектің нақты түрін автоматты түрде шығарады. Осы тілдердің бірі - Хаскелл, түсінікті болу үшін қарапайым мысал келтірейін:

Ашық түр спецификациясынсыз қосу (x, y) = x + y -- Ашық түр спецификациясын қосу: (Бүтін, бүтін) -> Бүтін қосу (х, у) = x + y

Ескерту: Мен әдейі өңделмеген функцияны қолдандым, сонымен қатар жалпы қосудың орнына әдейі жеке қолтаңба жаздым: (Num a) -> a -> a -> a , өйткені Мен Хаскелл синтаксисін түсіндірместен идеяны көрсеткім келді.

Хм. Көріп отырғанымыздай, бұл өте жақсы және қысқа. Функцияны жазу бос орындарды қосқанда бір жолда тек 18 таңбаны алады!

Дегенмен, автоматты түрдегі қорытынды өте күрделі нәрсе, тіпті Хаскелл сияқты керемет тілде ол кейде сәтсіздікке ұшырайды. (мысалы, мономорфизм шектеуі)

Әдепкі бойынша анық теру және қажет болса жасырын теру бар тілдер бар ма? Con
Әрине.

Таңдау бойынша жасырын теру

C++ 11 (бұрын C++0x деп аталатын) деп аталатын жаңа C++ тіл стандарты компиляторға контекстке негізделген түрді шығаруға мүмкіндік беретін auto кілт сөзін енгізді:

Салыстырайық: // unsigned түрін қолмен көрсету int a = 5; unsigned int b = a + 3; // unsigned түріндегі автоматты шығару int a = 5; авто b = a + 3;

Жаман емес. Бірақ жазба онша азайған жоқ. Итераторлармен мысалды қарастырайық (егер сіз түсінбесеңіз, қорықпаңыз, ең бастысы, автоматты түрде шығарудың арқасында жазба айтарлықтай азаяды):

// std::вектор түрін қолмен көрсету vec = randomVector(30); үшін (std::vector::const_iterator it = vec.cbegin(); ...) ( ... ) // Автоматты түрдегі қорытынды auto vec = randomVector (отыз); үшін (auto it = vec.cbegin(); ...) ( ... )

Мәссаған! Бұл аббревиатура. Жарайды, бірақ қайтару түрі аргументтердің түрлеріне байланысты болатын Хаскелл сияқты нәрсені жасауға болады ма?

Тағы да жауап иә, auto-мен тіркесетін decltype кілт сөзінің арқасында:

// Қолмен түрі int divide(int x, int y) ( ... ) // Автоматты түрдегі қорытындыны автоматты түрде бөлу(int x, int y) -> decltype(x / y) ( ... )

Белгілеудің бұл түрі өте жақсы көрінбеуі мүмкін, бірақ жалпы бағдарламалаумен (үлгілер/генериктермен) үйлескенде жасырын теру немесе автоматты түрдегі қорытынды ғажайыптар жасайды.

Осы классификацияға сәйкес кейбір бағдарламалау тілдері

Мен танымал тілдердің шағын тізімін беремін және олардың әр «теру» санатына қалай бөлінгенін жазамын.

JavaScript - динамикалық / әлсіз / жасырын Ruby - динамикалық / күшті / жасырын Python - динамикалық / күшті / жасырын Java - статикалық / күшті / айқын PHP - динамикалық / әлсіз / жасырын C - статикалық / әлсіз / айқын C++ - статикалық / жартылай күшті / Ашық Perl - динамикалық / әлсіз / жасырын мақсат-C - статикалық / әлсіз / айқын C# - статикалық / күшті / айқын Haskell - статикалық / күшті / жасырын Common Lisp - динамикалық / күшті / жасырын

Мүмкін мен бір жерде қателескен шығармын, әсіресе CL, PHP және Obj-C-де, егер сізде қандай да бір тіл туралы басқа пікіріңіз болса, түсініктемелерде жазыңыз.

Қорытынды

ЖАРАЙДЫ МА. Жақында ол жеңіл болады және мен теру туралы айтатын ештеңе жоқ деп ойлаймын. О, қалай? Тақырып түбі жоқ па? Айтылмай қалғаны көп пе? Түсініктемелерде пайдалы ақпаратпен бөлісіңіз.

Алғы шарттар

Қатаң теру келесі міндетті шарттарды орындауды білдіреді:

  1. Тілдегі кез келген деректер объектісінің (айнымалы, тұрақты, өрнек) әрқашан қатаң анықталған типі болады, ол бағдарламаны құрастыру (статикалық теру) кезінде бекітіледі немесе орындалу уақытында (динамикалық теру) анықталады.
  2. Айнымалыға айнымалымен бірдей деректер түріне ие мәнді ғана тағайындауға рұқсат етіледі; бірдей шектеулер параметрлерді беру және функция нәтижелерін қайтару үшін қолданылады.
  3. Әрбір операция қатаң анықталған түрлердің параметрлерін талап етеді.
  4. Жасырын түр түрлендіруге рұқсат етілмейді (яғни аудармашы айнымалы, параметр, функция немесе операция үшін жарияланғаннан басқа түрдің мәнін пайдалану әрекетін синтаксистік қате ретінде қарастырады).

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

Бағдарламалау тілдерінде теру

Сілтемелер

да қараңыз


Викимедиа қоры. 2010.

Басқа сөздіктерде «Қатты теру» деген не екенін қараңыз:

    Мәліметтер түрі бағдарламалау теориясындағы негізгі ұғым болып табылады. Деректер түрі мәндер жиынын, сол мәндерге қолдануға болатын әрекеттер жиынтығын және мүмкін мәндерді сақтау мен операцияларды орындау жолын анықтайды. Кез келген... ... Википедия

    Деректерді теру Түр қауіпсіздігі Түрді қорытындылау Динамикалық теру Статикалық теру Күшті теру Жұмсақ теру Тәуелді түрлер Үйрек теру Негізгі мақала: Күшті теру Динамикалық теру - кең таралған әдіс... ... Wikipedia

    Деректерді теру Түр қауіпсіздігі Түрді қорытындылау Динамикалық теру Статикалық теру Күшті теру Жұмсақ теру Тәуелді түрлер Үйрекпен теру Негізгі мақала: Күшті теру Статикалық теру - кең таралған әдіс... ... Wikipedia

    Динамикалық теру - бағдарламалау тілдерінде және спецификация тілдерінде кеңінен қолданылатын әдіс, онда айнымалы айнымалыны жариялау сәтінде емес, мәнді тағайындау сәтінде түрмен байланыстырылады. Осылайша, әртүрлі салаларда ... Уикипедия

    Деректерді теру Түр қауіпсіздігі Түрді қорытындылау Динамикалық теру Статикалық теру Күшті теру Жұмсақ теру Тәуелді түрлер Үйрекпен теру Бағдарламалаудағы типті шығару компилятор мүмкіндігі... ... Wikipedia

    Деректерді теру Түр қауіпсіздігі Түрді қорытындылау Динамикалық теру Статикалық теру Күшті теру Жұмсақ теру Тәуелді түрлер Үйрекпен теру Тәуелді түр, информатика мен логикада, мәнге тәуелді түр. Тәуелділер... ... Wikipedia

    - (деректер типі термині де кездеседі) программалау теориясының іргелі тұжырымдамасы болып табылады. Деректер түрі мәндер жиынын, осындай мәндерге қолдануға болатын операциялар жинағын және мүмкін мәндерді сақтауды жүзеге асыру жолын және... ... Wikipedia анықтайды.

    Деректер түрі Мазмұны 1 Тарих 2 Анықтама 3 Деректер түрлерін пайдалану қажеттілігі ... Уикипедия

    Бұл терминнің басқа да мағыналары бар, ML (мағыналарын) қараңыз. ML Семантика: көп парадигма: функционалды, императивті, модульдік Шығару жылы: 1973 Автор(лар): Робин Милнер және басқалар Эдинбург университеті ... Уикипедия