Ce este tastarea dinamică? Tastare dinamică Tastare statică PHP.

Totul este foarte simplu. Este ca diferența dintre un hotel și un apartament privat.

In apartament locuiesc doar cei care sunt inregistrati acolo. Dacă, să zicem, familia Sidorov trăiește în ea, atunci familia Pupkin, pentru viața noastră, nu poate trăi acolo. În același timp, Petya Sidorov poate locui în acest apartament, apoi Grisha Sidorov se poate muta acolo (uneori chiar pot locui acolo în același timp - aceasta este o matrice). Aceasta este tastare statică.

Familia Sidorov poate locui la hotel la un moment dat. Nici măcar nu trebuie să se înregistreze întotdeauna acolo. Apoi vor pleca de acolo, iar Pupkins se vor muta acolo. Și apoi Kuznețov. Și apoi altcineva. Aceasta este tastare dinamică.

Dacă revenim la programare, atunci primul caz (tasare statică) se găsește în, să zicem, limbajele C, C++, C#, Java și altele. Înainte de a atribui o valoare unei variabile pentru prima dată, ar trebui să spuneți ce veți stoca acolo: numere întregi, numere în virgulă mobilă, șiruri de caractere etc. ( soţii Sidorov vor locui în acest apartament). Tastarea dinamică, pe de altă parte, nu necesită acest lucru. Când atribuiți o valoare, atribuiți simultan variabilei tipul acesteia ( Vasya Pupkin din familia Pupkin locuiește acum în această cameră de hotel). Acesta se găsește în limbi precum PHP, Python și JavaScript.

Ambele abordări au avantajele și dezavantajele lor. Care dintre ele este mai bună sau mai proastă depinde de problemele rezolvate. Puteți citi mai multe în detaliu, să zicem, pe Wikipedia.

Cu tastarea statică, știți exact tipul de variabilă în momentul scrierii programului și dezvoltării algoritmului și luați în considerare acest lucru. acestea. dacă ați spus că variabila G este un întreg fără semn de patru octeți, atunci în algoritm va fi întotdeauna un întreg fără semn de patru octeți (dacă este ceva, atunci trebuie să îl convertiți în mod explicit sau să știți cum îl convertește traducătorul într-un anumit gamă de situații, dar în principal, dacă există o nepotrivire de tip, este o eroare în algoritm, iar compilatorul vă va avertiza cel puțin), cu una statică, nu puteți pune șirul „Vasya prostul” în număr și verificări suplimentare înainte de a utiliza variabila pentru a determina „există un număr acolo” nu sunt necesare, efectuați toată corectitudinea datelor în momentul introducerii lor în program sau așa cum este cerut de algoritmul însuși.

cu tastarea dinamică, tipul aceleiași variabile vă este în general necunoscut și se poate schimba deja în timpul execuției programului și luați în considerare acest lucru, nimeni nu vă va avertiza despre o potențială eroare a algoritmului din cauza unei nepotriviri de tip (când ați dezvoltat algoritmul ați presupus că G este un număr întreg, iar utilizatorul a introdus, să zicem, un număr în virgulă mobilă, sau mai rău, un șir, sau să spunem, după o operație aritmetică, în loc de un număr întreg, a existat un număr în virgulă mobilă , iar în pasul următor veți încerca să utilizați operațiuni cu biți...), pe de altă parte, nu trebuie să vă faceți griji pentru multe lucruri mărunte.

  • Tastarea dinamică este o tehnică utilizată pe scară largă în limbajele de programare și limbajele de specificare, în care o variabilă este asociată cu un tip în momentul atribuirii unei valori, și nu în momentul declarării variabilei. Astfel, în diferite părți ale programului, aceeași variabilă poate lua valori de diferite tipuri. Exemple de limbaje cu tastare dinamică sunt Smalltalk, Python, Objective-C, Ruby, PHP, Perl, JavaScript, Lisp, xBase, Erlang, Visual Basic.

    Tehnica opusă este tastarea statică.

    În unele limbi cu tastare dinamică slabă, există o problemă cu compararea valorilor, de exemplu, PHP are operatori de comparare „==”, „!=” și „===”, „!==”, unde al doilea perechea de operații compară valori și tipuri de variabile. Operația „===” dă adevărată numai dacă există o potrivire completă, spre deosebire de „==”, care consideră că următoarea expresie este adevărată: (1=="1"). Este de remarcat faptul că aceasta nu este o problemă cu tastarea dinamică în general, ci cu limbaje de programare specifice.

Concepte înrudite

Un limbaj de programare este un limbaj formal conceput pentru scrierea de programe de calculator. Un limbaj de programare definește un set de reguli lexicale, sintactice și semantice care determină aspectul programului și acțiunile pe care executantul (de obicei un computer) le va efectua sub controlul său.

Zahărul sintactic într-un limbaj de programare este caracteristicile sintactice, a căror utilizare nu afectează comportamentul programului, dar face ca utilizarea limbajului să fie mai convenabilă pentru oameni.

O proprietate este o modalitate de a accesa starea internă a unui obiect, simulând o variabilă de un anumit tip. Accesarea unei proprietăți a unui obiect arată la fel ca accesarea unui câmp de structură (în programarea structurată), dar este implementată de fapt printr-un apel de funcție. Când încercați să setați valoarea unei proprietăți date, o metodă este apelată, iar când încercați să obțineți valoarea acestei proprietăți, este apelată o altă metodă.

Extended Backus–Naur Form (EBNF) este un sistem formal de definire a sintaxei în care unele categorii sintactice sunt definite secvenţial prin altele. Folosit pentru a descrie gramatici formale fără context. Sugerat de Niklaus Wirth. Este o prelucrare extinsă a formelor Backus-Naur, se deosebește de BNF prin modele mai „capabile”, permițând, cu aceeași capacitate expresivă, simplificarea...

Programarea aplicativă este un tip de programare declarativă în care scrierea unui program constă în aplicarea sistematică a unui obiect la altul. Rezultatul unei astfel de aplicații este din nou un obiect care poate participa la aplicații atât ca funcție, cât și ca argument și așa mai departe. Acest lucru face notația programului clară din punct de vedere matematic. Faptul că o funcție este notă printr-o expresie indică posibilitatea utilizării funcțiilor-valoare - funcționale...

Un limbaj de programare concatenativ este un limbaj de programare bazat pe ideea că concatenarea a două bucăți de cod exprimă compoziția lor. Într-un astfel de limbaj, indicarea implicită a argumentelor funcției este utilizată pe scară largă (vezi programarea inutilă), noile funcții sunt definite ca o compoziție de funcții, iar concatenarea este folosită în locul aplicației. Această abordare este în contrast cu programarea aplicativă.

O variabilă este un atribut al unui sistem fizic sau abstract care își poate schimba valoarea, de obicei numerică. Conceptul de variabilă este utilizat pe scară largă în domenii precum matematică, știință, inginerie și programare. Exemple de variabile includ: temperatura aerului, parametrul funcției și multe altele.

Analiza sintactică (sau parsing, jargon parsing ← engleză parsing) în lingvistică și informatică este procesul de comparare a unei secvențe liniare de lexeme (cuvinte, simboluri) a unei limbi naturale sau formale cu gramatica sa formală. Rezultatul este de obicei un arbore de analiză (arborele de sintaxă). Folosit de obicei împreună cu analiza lexicală.

Un tip de date algebrice generalizate (GADT) este unul dintre tipurile de tipuri de date algebrice, care se caracterizează prin faptul că constructorii săi pot returna alte valori decât tipul asociat acestuia. Proiectat sub influența lucrărilor asupra familiilor inductive în rândul cercetătorilor de tipuri dependente.

Semantica în programare este o disciplină care studiază formalizarea semnificațiilor constructelor limbajului de programare prin construirea modelelor lor matematice formale. Diverse instrumente pot fi utilizate ca instrumente pentru construirea unor astfel de modele, de exemplu, logica matematică, λ-calcul, teoria mulțimilor, teoria categoriilor, teoria modelelor și algebra universală. Formalizarea semanticii unui limbaj de programare poate fi folosită pentru a descrie limbajul, a defini proprietățile limbajului...

Programarea orientată pe obiecte (OOP) este o metodologie de programare bazată pe reprezentarea unui program ca o colecție de obiecte, fiecare dintre acestea fiind o instanță a unei clase specifice, iar clasele formează o ierarhie de moștenire.

O variabilă dinamică este o variabilă dintr-un program, spațiu în RAM pentru care este alocat în timpul execuției programului. În esență, este o secțiune de memorie alocată de sistem unui program în scopuri specifice în timp ce programul rulează. Acesta este modul în care diferă de o variabilă statică globală - o bucată de memorie alocată de sistem unui program în scopuri specifice înainte ca programul să înceapă să ruleze. O variabilă dinamică este una dintre clasele de variabile de memorie.

Acest articol explică diferențele dintre limbile tip static și dinamic, examinează conceptele de tastare „puternică” și „slabă” și compară puterea sistemelor de tastare în diferite limbi. Recent, a existat o mișcare clară către sisteme de tastare mai stricte și mai puternice în programare, așa că este important să înțelegem despre ce vorbim când vorbim despre tipuri și tastare.



Un tip este o colecție de valori posibile. Un număr întreg poate avea valorile 0, 1, 2, 3 și așa mai departe. Booleanul poate fi adevărat sau fals. Puteți veni cu propriul tip, de exemplu, tipul „High Five”, în care valorile posibile sunt „high” și „5”, și nimic altceva. Nu este un șir sau un număr, este un tip nou, separat.


Limbile tipizate static restricționează tipurile de variabile: un limbaj de programare ar putea ști, de exemplu, că x este un număr întreg. În acest caz, programatorului îi este interzis să facă x = true, acesta va fi un cod incorect. Compilatorul va refuza să îl compileze, așa că nici măcar nu vom putea rula codul. Un alt limbaj tipizat static ar putea avea capacități expresive diferite și niciunul dintre sistemele de tip populare nu poate exprima tipul nostru HighFive (dar mulți pot exprima alte idei mai sofisticate).


Limbile tipizate dinamic marchează valorile cu tipuri: limba știe că 1 este un întreg, 2 este un întreg, dar nu poate ști că variabila x conține întotdeauna un întreg.


Runtime-ul limbajului verifică aceste etichete în momente diferite. Dacă încercăm să adăugăm două valori, poate verifica dacă sunt numere, șiruri sau matrice. Apoi va adăuga aceste valori, le va lipi sau va arunca o eroare, în funcție de tip.

Limbi tipizate static

Limbajele statice verifică tipurile dintr-un program în timpul compilării, înainte ca programul să ruleze. Orice program în care tipurile încalcă regulile limbii este considerat incorect. De exemplu, majoritatea limbilor statice vor respinge expresia „a” + 1 (C este o excepție de la această regulă). Compilatorul știe că „a” este un șir și 1 este un număr întreg și că + funcționează numai atunci când părțile din stânga și din dreapta sunt de același tip. Deci nu trebuie să ruleze programul pentru a realiza că există o problemă. Fiecare expresie dintr-un limbaj tipizat static este de un tip specific, care poate fi determinat fără a rula cod.


Multe limbi tipizate static necesită o denotație a tipului. Funcția Java public int add(int x, int y) ia două numere întregi și returnează un al treilea număr întreg. Alte limbi tipizate static pot deduce tipul automat. Aceeași funcție de adunare în Haskell arată astfel: adăugați x y = x + y . Nu îi spunem limbajului tipurile, dar poate să le descopere singur, deoarece știe că + funcționează numai pe numere, deci x și y trebuie să fie numere, așa că funcția de adunare ia două numere ca argumente.


Acest lucru nu reduce natura „statică” a sistemului de tip. Sistemul de tip Haskell este renumit pentru că este static, strict și puternic, iar Haskell este înaintea Java pe toate aceste fronturi.

Limbi tipizate dinamic

Limbile tastate dinamic nu necesită specificarea tipului, dar nu îl definesc ele însele. Tipurile de variabile sunt necunoscute până când au valori specifice la pornire. De exemplu, o funcție în Python


def f(x, y): returnează x + y

putem adăuga două numere întregi, concatenează șiruri, liste și așa mai departe și nu putem înțelege ce se întâmplă exact până când rulăm programul. Este posibil ca funcția f să fie apelată cu două șiruri la un moment dat și cu două numere la alt moment. În acest caz, x și y vor conține valori de diferite tipuri în momente diferite. Acesta este motivul pentru care se spune că valorile în limbaje dinamice au un tip, dar variabilele și funcțiile nu au. Valoarea 1 este cu siguranță un număr întreg, dar x și y pot fi orice.

Comparaţie

Majoritatea limbajelor dinamice vor genera o eroare dacă tipurile sunt utilizate incorect (JavaScript este o excepție notabilă; încearcă să returneze o valoare pentru orice expresie, chiar și atunci când nu are sens). Când utilizați limbaje tastate dinamic, chiar și o eroare simplă precum „a” + 1 poate apărea într-un mediu de producție. Limbajele statice previn astfel de erori, dar, desigur, gradul de prevenire depinde de puterea sistemului de tip.


Limbajele statice și dinamice sunt construite pe idei fundamental diferite despre corectitudinea programelor. Într-un limbaj dinamic, „a” + 1 este un program valid: codul va rula și o eroare va apărea în mediul de rulare. Cu toate acestea, în majoritatea limbilor tipizate static, expresia „a” + 1 este nu un program: Nu se va compila și nu va rula. Acesta este un cod incorect, la fel ca un set de caractere aleatorii!&%^@*&%^@* este un cod incorect. Acest concept suplimentar de corectitudine și incorectitudine nu are echivalent în limbajele dinamice.

Tastare puternică și slabă

Conceptele de „puternic” și „slab” sunt foarte ambigue. Iată câteva exemple de utilizare a acestora:

    Uneori „puternic” înseamnă „static”.
    Este simplu, dar este mai bine să folosiți termenul „static” pentru că majoritatea oamenilor îl folosesc și îl înțeleg.

    Uneori, „puternic” înseamnă „nu face conversie implicită de tip”.
    De exemplu, JavaScript vă permite să scrieți „a” + 1, care poate fi numit „tastare slabă”. Dar aproape toate limbile oferă un anumit nivel de conversie implicită care vă permite să convertiți automat din numere întregi în numere cu virgulă mobilă, cum ar fi 1 + 1.1. În realitate, majoritatea oamenilor folosesc cuvântul „puternic” pentru a defini granița dintre conversia acceptabilă și inacceptabilă. Nu există o limită general acceptată; toate sunt imprecise și depind de opinia unei anumite persoane.

    Uneori, „puternic” înseamnă că este imposibil să ocoliți regulile stricte de tastare ale limbii.

  • Uneori, „puternic” înseamnă sigur pentru memorie.
    C este un exemplu de limbaj nesigur pentru memorie. Dacă xs este o matrice de patru numere, atunci C va executa cu plăcere xs sau xs , returnând o valoare din memorie imediat în spatele xs .

Să ne oprim. Iată cum unele limbi îndeplinesc aceste definiții. După cum puteți vedea, doar Haskell este în mod constant „puternic” din toate punctele de vedere. Majoritatea limbilor nu sunt atât de clare.



(„Când ca” din coloana „Conversii implicite” înseamnă că împărțirea între puternic și slab depinde de conversiile pe care le considerăm acceptabile).


Adesea, termenii „puternic” și „slab” se referă la o combinație vagă a diferitelor definiții de mai sus și altele care nu sunt prezentate aici. Toată această confuzie face ca cuvintele „puternic” și „slab” să fie aproape fără sens. Când doriți să folosiți acești termeni, este mai bine să descrieți ce înseamnă exact. De exemplu, ați putea spune că „JavaScript returnează o valoare când este adăugat un șir cu un număr, dar Python returnează o eroare”. În acest caz, nu ne vom pierde energia încercând să ajungem la un acord cu privire la semnificațiile multiple ale cuvântului „puternic”. Sau, și mai rău: vom ajunge cu neînțelegeri nerezolvate din cauza terminologiei.


De cele mai multe ori, termenii „puternic” și „slab” de pe internet sunt opinii vagi și prost definite ale unor anumite persoane. Sunt folosite pentru a numi un limbaj „rău” sau „bun”, iar această opinie se transformă în jargon tehnic.



Strong Typing: Un sistem de tipare pe care îl iubesc și cu care mă simt confortabil.

Tastare slabă: un sistem de tip care mă deranjează sau cu care nu mă simt confortabil.

Tastarea treptată

Este posibil să adăugați tipuri statice limbilor dinamice? În unele cazuri - da. În altele este dificil sau imposibil. Cea mai evidentă problemă este eval și alte caracteristici similare ale limbajelor dinamice. Făcând 1 + eval("2") în Python rezultă 3. Dar ce oferă 1 + eval(read_from_the_network())? Depinde de ceea ce este online în momentul execuției. Dacă obținem un număr, atunci expresia este corectă. Dacă este un șir, atunci nu. Nu există nicio modalitate de a ști înainte de a rula, așa că nu este posibil să parsezi tipul static.


O soluție nesatisfăcătoare în practică este să setați expresia eval() la tipul Any, care este similară cu Object în unele limbaje de programare orientate pe obiecte sau interfață() în Go: este un tip care poate fi satisfăcut de orice valoare.


Valorile de tip Any sunt nerestricționate, astfel încât capacitatea sistemului de tip de a ne ajuta cu codul de evaluare dispare. Limbile care au atât eval, cât și un sistem de tipări trebuie să renunțe la siguranța tipului ori de câte ori este utilizat eval.


Unele limbi au tastare opțională sau graduală: sunt dinamice în mod implicit, dar permit adăugarea unor adnotări statice. Python a adăugat recent tipuri opționale; TypeScript este un superset de JavaScript care are tipuri opționale; Flow efectuează o analiză statică a codului JavaScript vechi bun.


Aceste limbi oferă unele dintre beneficiile tastării statice, dar nu vor oferi niciodată garanțiile absolute ale limbilor cu adevărat statice. Unele funcții vor fi tastate static, iar altele vor fi tastate dinamic. Un programator ar trebui să fie întotdeauna conștient și să se ferească de diferență.

Compilarea codului tip static

La compilarea codului tip static, sintaxa este mai întâi verificată, ca în orice compilator. Apoi tipurile sunt verificate. Aceasta înseamnă că un limbaj static se poate plânge mai întâi de o eroare de sintaxă, iar după ce o remediază, se plânge de 100 de erori de tastare. Remedierea erorilor de sintaxă nu a creat acele 100 de erori de tastare. Compilatorul pur și simplu nu avea nicio modalitate de a detecta erorile de tip până când sintaxa a fost corectată.


Compilatoarele pentru limbaje statice pot genera de obicei cod mai rapid decât compilatoarele pentru limbaje dinamice. De exemplu, dacă compilatorul știe că funcția de adăugare acceptă numere întregi, atunci poate folosi instrucțiunea ADD nativă a procesorului. Un limbaj dinamic va verifica tipul în timpul execuției, alegând dintr-o varietate de funcții de adăugare în funcție de tipuri (adăugați numere întregi sau flotanți, sau concatenează șiruri sau poate liste?) sau trebuie să decidă că a apărut o eroare și tipurile nu se potrivesc . Toate aceste verificări necesită timp. Limbajele dinamice folosesc diverse trucuri pentru optimizare, cum ar fi compilarea JIT (just-in-time), unde codul este recompilat în timpul execuției după ce au fost obținute toate informațiile de tip necesare. Cu toate acestea, niciun limbaj dinamic nu poate egala viteza codului static bine scris într-o limbă precum Rust.

Argumente pentru tipurile statice și dinamice

Susținătorii unui sistem de tip static subliniază că, fără un sistem de tip, erorile simple pot duce la probleme în producție. Acest lucru este, desigur, adevărat. Oricine a folosit un limbaj dinamic a experimentat acest lucru direct.


Susținătorii limbajelor dinamice subliniază că astfel de limbi par să fie mai ușor de scris cod. Acest lucru este cu siguranță adevărat pentru unele tipuri de cod pe care le scriem din când în când, cum ar fi acel cod de evaluare. Aceasta este o soluție controversată pentru munca obișnuită și aici are sens să ne amintim cuvântul vag „ușor”. Rich Hickey a făcut o treabă grozavă vorbind despre cuvântul „ușor” și legătura acestuia cu cuvântul „simplu”. După vizionarea acestui raport, veți înțelege că nu este ușor să folosiți corect cuvântul „ușor”. Atenție la „ușor”.


Avantajele și dezavantajele sistemelor de tastare statică și dinamică sunt încă puțin înțelese, dar cu siguranță depind de limbaj și de problema specifică rezolvată.


JavaScript încearcă să continue chiar dacă înseamnă o conversie fără sens (cum ar fi „a” + 1 rezultând „a1”). Python, pe de altă parte, încearcă să fie conservator și returnează adesea erori, ca în cazul „a” + 1 .


Există abordări diferite cu diferite niveluri de securitate, dar Python și JavaScript sunt ambele limbaje tipizate dinamic.



Haskell nu vă va permite să adăugați un număr întreg și un float fără o conversie explicită mai întâi. C și Haskell sunt ambele tipizate static, în ciuda diferențelor atât de mari.


Există multe variații ale limbajelor dinamice și statice. Orice declarație generală precum „limbajele statice sunt mai bune decât limbajele dinamice când vine vorba de X” este aproape garantată a fi o prostie. Acest lucru poate fi adevărat în cazul unor limbi specifice, dar atunci este mai bine să spuneți „Haskell este mai bun decât Python când vine vorba de X”.

Varietate de sisteme de tastare statică

Să aruncăm o privire la două exemple celebre de limbi tipizate static: Go și Haskell. Sistemul de tastare Go nu are tipuri generice, tipuri cu „parametri” din alte tipuri. De exemplu, ne putem crea propriul tip pentru listele MyList, care poate stoca orice date de care avem nevoie. Dorim să putem crea o MyList de numere întregi, o MyList de șiruri de caractere și așa mai departe, fără a modifica codul sursă MyList. Compilatorul trebuie să țină cont de tastare: dacă există o Lista My de numere întregi și adăugăm accidental un șir acolo, atunci compilatorul trebuie să respingă programul.


Go a fost conceput special pentru a nu permite definirea unor tipuri precum MyList. Cel mai bun lucru care se poate face este să creați o MyList de „interfețe goale”: MyList poate conține obiecte, dar compilatorul pur și simplu nu le cunoaște tipul. Când recuperăm obiecte din MyList, trebuie să spunem compilatorului tipul lor. Dacă spunem „Primesc un șir”, dar în realitate valoarea este un număr, atunci va exista o eroare de rulare, așa cum este cazul limbajelor dinamice.


De asemenea, Go nu are multe dintre celelalte caracteristici găsite în limbile moderne tipizate static (sau chiar unele sisteme din anii 1970). Creatorii lui Go au avut motivele lor pentru aceste decizii, dar opiniile celor din afară pe această temă pot suna uneori dure.


Acum să comparăm cu Haskell, care are un sistem de tip foarte puternic. Dacă setați tipul la MyList, atunci tipul „listei de numere” este pur și simplu MyList Integer . Haskell ne va împiedica să adăugăm accidental un șir în listă și se va asigura că nu punem un element din listă într-o variabilă șir.


Haskell poate exprima idei mult mai complexe direct cu tipuri. De exemplu, Num a => MyList a înseamnă „MyList de valori care aparțin aceluiași tip de numere”. Ar putea fi o listă de numere întregi, flotanți sau zecimale cu precizie fixă, dar cu siguranță nu va fi niciodată o listă de șiruri, care este verificată în timpul compilării.


Puteți scrie o funcție de adăugare care funcționează cu orice tip numeric. Această funcție va avea tipul Num a => (a -> a -> a) . Inseamna:

  • a poate fi orice tip numeric (Num a =>).
  • Funcția ia două argumente de tip a și returnează tipul a (a -> a -> a).

Ultimul exemplu. Dacă tipul funcției este String -> String , atunci acceptă un șir și returnează un șir. Dar dacă este String -> IO String , atunci face și unele I/O. Aceasta ar putea fi accesarea unui disc, accesarea unei rețele, citirea de pe un terminal și așa mai departe.


Dacă funcția are tip Nu IO, atunci știm că nu efectuează nicio operație I/O. Într-o aplicație web, de exemplu, puteți spune dacă o funcție modifică baza de date pur și simplu uitându-vă la tipul acesteia. Nicio limbă dinamică și aproape nicio limbă statică nu poate face acest lucru. Aceasta este o caracteristică a limbilor cu cele mai puternice sisteme de tastare.


În majoritatea limbilor, ar trebui să parcurgem o funcție și toate funcțiile care sunt apelate de acolo și așa mai departe, încercând să găsim ceva care să schimbe baza de date. Acesta este un proces obositor și ușor de făcut greșeli. Și sistemul de tip Haskell poate răspunde la această întrebare simplu și fiabil.


Comparați această putere cu Go, care nu poate exprima ideea simplă a MyList, darămite „o funcție care ia două argumente, atât numerice, cât și de același tip, și care face I/O”.


Abordarea Go facilitează scrierea instrumentelor de programare Go (în special, implementarea compilatorului poate fi simplă). În plus, există mai puține concepte de învățat. Cum se compară aceste beneficii cu limitările semnificative este o întrebare subiectivă. Cu toate acestea, nu există niciun argument că Haskell este mai greu de învățat decât Go și că sistemul de tip Haskell este mult mai puternic și că Haskell poate preveni mult mai multe tipuri de erori la compilare.


Go și Haskell sunt limbi atât de diferite încât gruparea lor în aceeași clasă de „limbi statice” poate induce în eroare, chiar dacă termenul este folosit corect. Când comparăm beneficiile practice de securitate, Go este mai aproape de limbajele dinamice decât Haskell.


Pe de altă parte, unele limbi dinamice sunt mai sigure decât unele limbi statice. (Python este, în general, considerat mult mai sigur decât C). Când doriți să faceți generalizări despre limbile statice sau dinamice ca grupuri, nu uitați de numărul imens de diferențe dintre limbi.

Exemple specifice de diferențe în capacitățile sistemelor de tastare

Sistemele de tastare mai puternice pot specifica constrângeri la niveluri mai mici. Iată câteva exemple, dar nu vă agățați prea mult de ele dacă sintaxa nu este clară.


În Go puteți spune „funcția de adăugare ia două numere întregi și returnează un număr întreg”:


func add(x int, y int) int ( return x + y )

În Haskell puteți spune „o funcție ia orice tip numeric și returnează un număr de același tip":


f:: Num a => a -> a -> a adăuga x y = x + y

În Idris puteți spune „funcția ia două numere întregi și returnează un număr întreg, dar primul argument trebuie să fie mai mic decât al doilea argument”:


adăugați: (x: Nat) -> (y: Nat) -> (auto mai mic: LT x y) -> Nat adăugați x y = x + y

Dacă încercați să apelați funcția add 2 1 unde primul argument este mai mare decât al doilea, compilatorul va respinge programul la momentul compilarii. Este imposibil să scrieți un program în care primul argument este mai mare decât al doilea. Rareori o limbă are această capacitate. În majoritatea limbilor, această verificare are loc în timpul execuției: am scrie ceva de genul if x >= y: raise SomeError() .


Nu există echivalent Haskell cu tipul din exemplul Idris de mai sus și nu există echivalent Go cu nici exemplul Haskell, fie cu cel Idris. Drept urmare, Idris poate preveni multe erori pe care Haskell nu le poate preveni, iar Haskell poate preveni multe erori pe care Go nu le va observa. În ambele cazuri, sunt necesare capacități suplimentare ale sistemului de tastare pentru a face limbajul mai complex.

Sisteme de tastare ale unor limbaje statice

Iată o listă aproximativă a sistemelor de tastare ale unor limbi, în ordinea creșterii puterii. Această listă vă va oferi o idee generală despre puterea sistemelor, nu o tratați ca pe un adevăr absolut. Limbile colectate într-un grup pot fi foarte diferite unele de altele. Fiecare sistem de tastare are ciudateniile sale, iar cele mai multe dintre ele sunt foarte complexe.

  • C (1972), Go (2009): Aceste sisteme nu sunt deloc puternice, fără suport pentru tipurile generice. Nu este posibil să se definească un tip MyList care ar însemna „listă de numere întregi”, „listă de șiruri de caractere”, etc. În schimb, va trebui să faceți o „listă de valori nedesemnate”. Programatorul trebuie să raporteze manual „aceasta este o listă de șiruri” de fiecare dată când un șir este preluat din listă și acest lucru poate duce la o eroare de execuție.
  • Java (1995), C# (2000): Ambele limbi acceptă tipuri generice, așa că ați putea spune MyList și obțineți o listă de șiruri despre care compilatorul le cunoaște și poate impune regulile de tip. Elementele din listă vor fi de tip String, iar compilatorul va forța regulile de compilare ca de obicei, astfel încât erorile de rulare sunt mai puțin probabile.
  • Haskell (1990), Rust (2010), Swift (2014): Toate aceste limbaje au mai multe caracteristici avansate, inclusiv tipuri generice, tipuri de date algebrice (ADT) și clase de tip sau ceva similar (tipuri de clasă, trăsături și, respectiv, protocoale). Rust și Swift sunt mai populare decât Haskell și sunt promovate de organizații mari (Mozilla și, respectiv, Apple).
  • Agda (2007), Idris (2011): Aceste limbi acceptă tipuri dependente, permițându-vă să creați tipuri precum „o funcție care ia două numere întregi x și y, unde y este mai mare decât x”. Chiar și constrângerea „y este mai mare decât x” este forțată în timpul compilării. Când este executat, y nu va fi niciodată mai mic sau egal cu x, indiferent de ce se întâmplă. Proprietățile foarte subtile, dar importante ale unui sistem pot fi verificate static în aceste limbi. Foarte puțini programatori le studiază, dar aceste limbaje trezesc un mare entuziasm în rândul lor.

Există o mișcare clară către sisteme de dactilografiere mai puternice, mai ales după cum se măsoară prin popularitatea limbilor, mai degrabă decât prin simplul fapt că există limbi. O excepție notabilă este Go, ceea ce explică de ce mulți susținători ai limbajelor statice îl consideră un pas înapoi.


Grupul doi (Java și C#) sunt limbi principale, mature și utilizate pe scară largă.


Grupul trei este pe punctul de a intra în mainstream, cu sprijin excelent din partea Mozilla (Rust) și Apple (Swift).


Grupa patru (Idris și Agda) sunt departe de mainstream, dar asta se poate schimba în timp. Limbile din grupa trei erau departe de curentul principal acum zece ani.

Acest articol conține minimul necesar dintre acele lucruri pe care pur și simplu trebuie să le știți despre tastare pentru a nu numi scrierea dinamică rău, Lisp un limbaj fără tip și C un limbaj puternic tastat.

Versiunea completă conține o descriere detaliată a tuturor tipurilor de tastare, asezonată cu exemple de cod, link-uri către limbaje de programare populare și imagini ilustrative.

Vă recomand să citiți mai întâi versiunea scurtă a articolului și apoi versiunea completă dacă doriți.

Versiune scurta

Pe baza tastării, limbajele de programare sunt de obicei împărțite în două tabere mari - tastate și netipizate (fără tip). Primul include, de exemplu, C, Python, Scala, PHP și Lua, iar al doilea include limbajul de asamblare, Forth și Brainfuck.

Deoarece „tastarea fără tip” în esența sa este la fel de simplă ca o priză, nu este împărțită în alte tipuri. Dar limbile tastate sunt împărțite în mai multe categorii care se suprapun:

  • Tastare statică/dinamică. Static este definit prin faptul că tipurile finale de variabile și funcții sunt setate în timpul compilării. Acestea. compilatorul este deja 100% sigur care tip este unde. În tastarea dinamică, toate tipurile sunt descoperite în timpul execuției programului.

    Exemple:
    Static: C, Java, C#;
    Dinamic: Python, JavaScript, Ruby.

  • Tastare puternică/slabă (uneori numită și puternic/lax). Tastarea puternică se distinge prin faptul că limbajul nu permite amestecarea diferitelor tipuri în expresii și nu efectuează conversii implicite automate, de exemplu, nu puteți scădea un set dintr-un șir. Limbile scrise slab realizează automat multe conversii implicite, chiar dacă poate apărea o pierdere de precizie sau conversia este ambiguă.

    Exemple:
    Puternic: Java, Python, Haskell, Lisp;
    Slab: C, JavaScript, Visual Basic, PHP.

  • Tastare explicită/implicite. Limbile scrise explicit diferă prin aceea că tipul de noi variabile/funcții/argumentele acestora trebuie specificat în mod explicit. În consecință, limbile cu tastare implicită transferă această sarcină către compilator/interpret.

    Exemple:
    Explicit: C++, D, C#
    Implicit: PHP, Lua, JavaScript

De asemenea, trebuie remarcat că toate aceste categorii se suprapun, de exemplu, limbajul C are o tastare statică slabă explicită, iar limbajul Python are o tastare dinamică puternică implicită.

Cu toate acestea, nu există limbi cu tastare statică și dinamică în același timp. Deși, privind în față, voi spune că zac aici - ele chiar există, dar mai multe despre asta mai târziu.

Versiune detaliată

Dacă versiunea scurtă nu a fost suficientă pentru tine, este în regulă. Nu degeaba am scris unul detaliat? Principalul lucru este că era pur și simplu imposibil să încadrezi toate informațiile utile și interesante într-o versiune scurtă, iar una detaliată ar fi probabil prea lungă pentru ca toată lumea să poată citi fără efort.

Tastare fără tip

În limbajele de programare fără tip, toate entitățile sunt considerate simple secvențe de biți de lungimi diferite.

Tastarea fără tip este de obicei inerentă limbajelor de nivel scăzut (limbaj de asamblare, Forth) și ezoterice (Brainfuck, HQ9, Piet). Cu toate acestea, pe lângă dezavantajele sale, are și câteva avantaje.

Avantaje
  • Vă permite să scrieți la un nivel extrem de scăzut, iar compilatorul/interpretul nu va interfera cu nicio verificare de tip. Sunteți liber să efectuați orice operațiuni pe orice tip de date.
  • Codul rezultat este de obicei mai eficient.
  • Transparența instrucțiunilor. Dacă cunoașteți limba, de obicei nu există nicio îndoială care este acest cod.
Defecte
  • Complexitate. Există adesea nevoia de a reprezenta valori complexe, cum ar fi liste, șiruri sau structuri. Acest lucru poate cauza neplăceri.
  • Lipsa controalelor. Orice acțiuni fără sens, cum ar fi scăderea unui indicator la o matrice dintr-un simbol, vor fi considerate complet normale, ceea ce este plin de erori subtile.
  • Nivel scăzut de abstractizare. Lucrul cu orice tip de date complex nu este diferit de lucrul cu numere, ceea ce desigur va crea multe dificultăți.
Tastare puternică fără tip?

Da, așa ceva există. De exemplu, în limbajul de asamblare (pentru arhitectura x86/x86-64, nu cunosc altele) nu puteți asambla un program dacă încercați să încărcați date din registrul rax (64 biți) în registrul cx (16 biți) .

mov cx, eax ; eroare de timp de asamblare

Deci, se pare că asamblatorul încă mai are tastarea? Cred că aceste verificări nu sunt suficiente. Și părerea ta, desigur, depinde doar de tine.

Tastare statică și dinamică

Principalul lucru care diferențiază tastarea statică de tastarea dinamică este că toate verificările de tip sunt efectuate în timpul compilării, nu în timpul rulării.

Unii oameni ar putea crede că tastarea statică este prea restrictivă (de fapt, este, dar aceasta a fost de mult eliminată cu ajutorul unor tehnici). Unii oameni spun că limbile tastate dinamic se joacă cu focul, dar ce caracteristici le fac să iasă în evidență? Ambele specii chiar au șansa de a exista? Dacă nu, atunci de ce există atât de multe limbi care sunt scrise atât static, cât și dinamic?

Să ne dăm seama.

Beneficiile tastării statice
  • Verificarea tipului are loc o singură dată - în etapa de compilare. Aceasta înseamnă că nu va trebui să ne dăm seama în mod constant dacă încercăm să împărțim un număr cu un șir (și fie să aruncăm o eroare, fie să realizăm o conversie).
  • Viteza de executie. Din punctul anterior, este clar că limbile tastate static sunt aproape întotdeauna mai rapide decât cele tastate dinamic.
  • În anumite condiții suplimentare, vă permite să detectați erori potențiale deja în etapa de compilare.
Beneficiile tastării dinamice
  • Ușurința de a crea colecții universale - grămezi de orice și de toată lumea (rar apare o astfel de nevoie, dar atunci când apare tastarea dinamică, aceasta va ajuta).
  • Comoditatea descrierii algoritmilor generalizați (de exemplu, sortarea matricei, care va funcționa nu numai pe o listă de numere întregi, ci și pe o listă de numere reale și chiar pe o listă de șiruri de caractere).
  • Ușor de învățat - Limbile tastate dinamic sunt de obicei foarte bune pentru a începe programarea.

Programare generalizată

Bine, cel mai important argument pentru tastarea dinamică este comoditatea descrierii algoritmilor generici. Să ne imaginăm o problemă - avem nevoie de o funcție pentru a căuta prin mai multe matrice (sau liste) - o matrice de numere întregi, o matrice de reali și o matrice de caractere.

Cum o vom rezolva? Să o rezolvăm în 3 limbi diferite: una cu tastare dinamică și două cu tastare statică.

Voi folosi unul dintre cei mai simpli algoritmi de căutare - forța brută. Funcția va primi elementul căutat, matricea (sau lista) în sine și va returna indexul elementului, sau dacă elementul nu este găsit - (-1).

Soluție dinamică (Python):

Def find(required_element, list): for (index, element) in enumerate(list): if element == required_element: return index return (-1)

După cum puteți vedea, totul este simplu și nu există probleme cu faptul că lista poate conține numere, liste sau alte matrice. Foarte bun. Să mergem mai departe - rezolvă aceeași problemă în C!

Soluție statică (C):

Unsigned int find_int(int required_element, int array, unsigned int size) (pentru (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); }

Ei bine, fiecare funcție în mod individual este similară cu versiunea Python, dar de ce sunt trei dintre ele? S-a pierdut cu adevărat programarea statică?

Da și nu. Există mai multe tehnici de programare, dintre care una o vom lua în considerare acum. Se numește programare generică și limbajul C++ o suportă destul de bine. Să aruncăm o privire la noua versiune:

Soluție statică (programare generică, C++):

Șablon unsigned int find(T required_element, std::vector matrice) (pentru (unsigned int i = 0; i< array.size(); ++i) if (required_element == array[i]) return i; return (-1); }

Amenda! Nu pare mult mai complicat decât versiunea Python și nu necesită mult scris. În plus, am primit o implementare pentru toate matricele, nu doar pentru cele 3 necesare pentru a rezolva problema!

Această versiune pare să fie exact ceea ce avem nevoie - obținem atât avantajele tastării statice, cât și unele dintre avantajele tastării dinamice.

Este grozav că acest lucru este posibil, dar ar putea fi și mai bine. În primul rând, programarea generalizată poate fi mai convenabilă și mai frumoasă (de exemplu, în limbajul Haskell). În al doilea rând, pe lângă programarea generalizată, puteți utiliza și polimorfismul (rezultatul va fi mai rău), supraîncărcarea funcțiilor (în mod similar) sau macrocomenzi.

Statica în dinamică

De asemenea, trebuie menționat că multe limbaje statice permit tastarea dinamică, de exemplu:

  • C# acceptă pseudo-tipul dinamic.
  • F# acceptă zahărul sintactic sub forma operatorului ?, pe baza căruia poate fi implementată imitarea tastării dinamice.
  • Haskell - tastarea dinamică este asigurată de modulul Data.Dynamic.
  • Delphi - printr-un tip Variant special.

De asemenea, unele limbi scrise dinamic vă permit să profitați de tastarea statică:

  • Common Lisp - declarații de tip.
  • Perl - din versiunea 5.6, destul de limitat.

Tastare puternică și slabă

Limbile puternic tastate nu permit amestecarea unor entități de diferite tipuri în expresii și nu efectuează conversii automate. Ele sunt numite și „limbi puternic tipizate”. Termenul englezesc pentru acest lucru este scriere puternică.

Limbajele slab tipizate, dimpotrivă, încurajează programatorul să amestece diferite tipuri într-o singură expresie, iar compilatorul însuși va reduce totul la un singur tip. Ele mai sunt numite și „limbi scrise liber”. Termenul în engleză pentru aceasta este scriere slabă.

Tastarea slabă este adesea confundată cu tastarea dinamică, care este complet greșită. Un limbaj tipizat dinamic poate fi scris slab sau puternic.

Cu toate acestea, puțini oameni acordă importanță stricteței la tastare. Se spune adesea că, dacă o limbă este tastată static, atunci puteți surprinde multe erori potențiale la compilare. Ei te mint!

Limba trebuie să aibă și o tastare puternică. Într-adevăr, dacă compilatorul, în loc să raporteze o eroare, adaugă pur și simplu un șir la un număr sau, și mai rău, scade altul dintr-o matrice, la ce ne folosește că toate „verificările” de tipuri vor fi la compilare etapă? Așa este - tastarea statică slabă este chiar mai rea decât tastarea dinamică puternică! (Ei bine, asta e parerea mea)

Deci tastarea slabă nu are deloc avantaje? Poate arăta așa, dar în ciuda faptului că sunt un susținător înfocat al tastării puternice, trebuie să fiu de acord că tastarea slabă are și avantaje.

Vrei să știi care dintre ele?

Beneficiile tastării puternice
  • Fiabilitate - Veți primi o excepție sau o eroare de compilare în loc de un comportament incorect.
  • Viteză – În loc de conversii ascunse, care pot fi destul de costisitoare, cu tastare puternică trebuie să le scrieți în mod explicit, ceea ce obligă programatorul să știe cel puțin că această bucată de cod poate fi lentă.
  • Înțelegerea modului în care funcționează programul - din nou, în loc de turnare implicită de tip, programatorul scrie totul el însuși, ceea ce înseamnă că înțelege aproximativ că compararea unui șir și a unui număr nu se întâmplă de la sine și nu prin magie.
  • Certitudine - atunci când scrii transformări de mână știi exact la ce te transformi și la ce. De asemenea, veți fi întotdeauna conștienți de faptul că astfel de conversii pot duce la pierderea preciziei și la rezultate incorecte.
Beneficiile tastării slabe
  • Comoditatea utilizării expresiilor mixte (de exemplu, din numere întregi și numere reale).
  • Abstracția de la tastare și concentrarea asupra sarcinii.
  • Concizia intrării.

Bine, ne-am dat seama, se dovedește că tastarea slabă are și avantaje! Există modalități de a transfera avantajele tastării slabe la tastarea puternică?

Se pare că sunt chiar două.

Casting de tip implicit, în situații lipsite de ambiguitate și fără pierderi de date

Wow... Un punct destul de lung. Permiteți-mi să o scurtez și mai mult la „conversie implicită limitată” Deci, ce înseamnă situația neechivocă și pierderea de date?

O situație fără ambiguitate este o transformare sau operație în care esența este imediat clară. De exemplu, adăugarea a două numere este o situație clară. Dar conversia unui număr într-o matrice nu este (poate că va fi creată o matrice cu un element, poate o matrice cu o astfel de lungime, umplută cu elemente în mod implicit și poate că numărul va fi convertit într-un șir și apoi într-o matrice de personaje).

Pierderea datelor este și mai ușoară. Dacă convertim numărul real 3,5 într-un număr întreg, vom pierde o parte din date (de fapt, această operație este și ea ambiguă - cum se va face rotunjirea? În sus? În jos? Înlăturarea părții fracționale?).

Conversiile în situații ambigue și conversiile cu pierdere de date sunt foarte, foarte proaste. Nu există nimic mai rău decât asta în programare.

Dacă nu mă credeți, studiați limbajul PL/I sau chiar căutați specificația acestuia. Are reguli pentru conversia între TOATE tipurile de date! Acesta este doar iadul!

Bine, să ne amintim despre conversia implicită limitată. Există astfel de limbi? Da, de exemplu în Pascal puteți converti un număr întreg într-un număr real, dar nu invers. Există și mecanisme similare în C#, Groovy și Common Lisp.

Bine, am spus că există încă o modalitate de a obține câteva avantaje ale tastării slabe într-o limbă puternică. Și da, există și se numește polimorfism constructor.

O voi explica folosind exemplul minunatului limbaj Haskell.

Constructorii polimorfi au apărut din observația că conversiile implicite sigure sunt cel mai adesea necesare atunci când se folosesc literali numerici.

De exemplu, în expresia pi + 1, nu doriți să scrieți pi + 1.0 sau pi + float(1) . Vreau doar să scriu pi + 1!

Și acest lucru se face în Haskell, datorită faptului că literalul 1 nu are un tip concret. Nu este nici întreg, nici real, nici complex. Este doar un număr!

Ca rezultat, atunci când scriem o funcție simplă sum x y , înmulțind toate numerele de la x la y (cu un increment de 1), obținem mai multe versiuni deodată - sumă pentru numere întregi, sumă pentru reale, sumă pentru raționale, sumă pentru numere complexe și chiar suma pentru toate acele tipuri numerice pe care le-ați definit.

Desigur, această tehnică salvează doar atunci când se utilizează expresii mixte cu literale numerice, iar acesta este doar vârful aisbergului.

Astfel, putem spune că cea mai bună soluție este de a echilibra pe marginea dintre tastarea puternică și slabă. Dar nicio limbă nu atinge încă echilibrul perfect, așa că înclin mai mult spre limbaje puternic tastate (cum ar fi Haskell, Java, C#, Python) decât spre cele slab tastate (cum ar fi C, JavaScript, Lua, PHP).

Tastare explicită și implicită

Un limbaj tipizat explicit necesită ca programatorul să specifice tipurile tuturor variabilelor și funcțiilor pe care le declară. Termenul englezesc pentru aceasta este tastarea explicită.

Un limbaj implicit tipizat, pe de altă parte, vă încurajează să uitați de tipuri și să lăsați sarcina de a deduce tipuri pe seama compilatorului sau interpretului. Termenul englezesc pentru aceasta este tastarea implicită.

La început, ați putea crede că tastarea implicită este echivalentă cu dinamica, iar tastarea explicită este echivalentă cu static, dar mai târziu vom vedea că nu este așa.

Există avantaje pentru fiecare tip și, din nou, există combinații ale acestora și există limbi care acceptă ambele metode?

Beneficiile tastării explicite
  • Dacă fiecare funcție are o semnătură (de exemplu, int add(int, int)) face ușor să determinați ce face funcția.
  • Programatorul notează imediat ce tip de valori pot fi stocate într-o anumită variabilă, eliminând nevoia de a o aminti.
Beneficiile tastării implicite
  • Notație scurtă - def add(x, y) este în mod clar mai scurtă decât int add(int x, int y) .
  • Rezistenta la schimbare. De exemplu, dacă într-o funcție variabila temporară a fost de același tip cu argumentul de intrare, atunci într-un limbaj tatat explicit, atunci când schimbați tipul argumentului de intrare, va trebui să schimbați și tipul variabilei temporare.

Bine, este clar că ambele abordări au atât argumente pro, cât și contra (cine se aștepta la altceva?), așa că haideți să căutăm modalități de a combina aceste două abordări!

Tastare explicită la alegere

Există limbaje cu tastare implicită în mod implicit și posibilitatea de a specifica tipul de valori dacă este necesar. Traducătorul va scoate automat tipul real de expresie. Una dintre aceste limbi este Haskell, permiteți-mi să dau un exemplu simplu pentru claritate:

Fără specificația explicită de tip adăugați (x, y) = x + y -- Specificația explicită de tip adăugați:: (întreg, întreg) -> întreg adăugați (x, y) = x + y

Notă: am folosit în mod intenționat o funcție necurriculară și, de asemenea, am scris în mod intenționat o semnătură privată în loc de adăugarea mai generală:: (Num a) -> a -> a -> a , deoarece Am vrut să arăt ideea fără a explica sintaxa Haskell.

Hm. După cum putem vedea, este foarte frumos și scurt. Scrierea unei funcții necesită doar 18 caractere pe o singură linie, inclusiv spațiile!

Cu toate acestea, inferența de tip automat este un lucru destul de complex și chiar și într-un limbaj atât de cool precum Haskell, uneori eșuează. (un exemplu este constrângerea monomorfismului)

Există limbi cu tastare explicită implicită și tastare implicită dacă este necesar? Con
sigur.

Tastare implicită la alegere

Noul standard de limbaj C++, numit C++11 (numit anterior C++0x), a introdus cuvântul cheie auto, care permite compilatorului să deducă tipul pe baza contextului:

Să comparăm: // Specificarea manuală a tipului unsigned int a = 5; unsigned int b = a + 3; // Ieșire automată de tip unsigned int a = 5; auto b = a + 3;

Nu-i rău. Dar înregistrarea nu a scăzut prea mult. Să ne uităm la un exemplu cu iteratoare (dacă nu înțelegeți, nu vă fie teamă, principalul lucru de reținut este că înregistrarea este mult redusă datorită ieșirii automate):

// Specificarea manuală a tipului std::vector vec = randomVector(30); for (std::vector::const_iterator it = vec.cbegin(); ...) ( ... ) // Inferență de tip automat auto vec = randomVector (treizeci); pentru (auto it = vec.cbegin(); ...) ( ... )

Wow! Aceasta este abrevierea. Bine, dar este posibil să faci ceva de genul Haskell, unde tipul de returnare depinde de tipurile de argumente?

Și din nou răspunsul este da, datorită cuvântului cheie decltype în combinație cu auto:

// Tip manual int divide(int x, int y) ( ... ) // Tip automat deducere auto divide(int x, int y) -> decltype(x / y) ( ... )

Această formă de notație poate să nu pară foarte bună, dar atunci când este combinată cu programarea generică (șabloane/generice), tastarea implicită sau inferența de tip automat face minuni.

Unele limbaje de programare conform acestei clasificări

Voi oferi o mică listă de limbi populare și voi scrie cum sunt împărțite în fiecare categorie de „tastare”.

JavaScript - Dinamic / Slab / Implicit Ruby - Dinamic / Puternic / Implicit Python - Dinamic / Puternic / Java implicit - Static / Puternic / PHP explicit - Dinamic / Slab / Implicit C - Static / Slab / Explicit C++ - Static / Semi-puternic / Perl explicit - Dinamic / Slab / Implicit Obiectiv-C - Static / Slab / Explicit C# - Static / Puternic / Explicit Haskell - Static / Puternic / Implicit Common Lisp - Dinamic / Puternic / Implicit

Poate am gresit undeva, mai ales cu CL, PHP si Obj-C, daca aveti alta parere despre vreo limba, scrieti in comentarii.

Concluzie

BINE. În curând va fi lumină și simt că nu mai este nimic de spus despre tastare. Oh, cum? Este subiectul fără fond? Au rămas multe nespuse? Vă rugăm să împărtășiți informații utile în comentarii.

Cerințe preliminare

Tastarea strictă implică îndeplinirea următoarelor condiții obligatorii:

  1. Orice obiect de date (variabilă, constantă, expresie) din limbaj are întotdeauna un tip strict definit, care este fixat în momentul compilării programului (tastare statică) sau determinat în timpul execuției (tastare dinamică).
  2. Este permisă atribuirea unei variabile doar unei valori care are exact același tip de date ca și variabilă, aceleași restricții se aplică la transmiterea parametrilor și la returnarea rezultatelor funcției.
  3. Fiecare operațiune necesită parametri de tipuri strict definiți.
  4. Conversia implicită a tipului nu este permisă (adică traducătorul tratează orice încercare de a utiliza o valoare de alt tip decât cea declarată pentru variabilă, parametru, funcție sau operație ca o eroare de sintaxă).

Dacă cerințele stricte de tastare sunt respectate cu strictețe, chiar și tipurile de date care sunt identice în compoziția valorilor și operațiunile permise sunt incompatibile. Dacă un program trebuie să aloce valoarea unui tip de date unei variabile de alt tip, acest lucru se poate face, dar numai prin aplicarea explicită a unei operații speciale de conversie a tipului, care în astfel de cazuri face de obicei parte din limbajul de programare (deși poate să nu fie în mod oficial unul, ci mai degrabă furnizat de biblioteci standard) .

Tastarea în limbaje de programare

Legături

Vezi si


Fundația Wikimedia. 2010.

Vedeți ce înseamnă „Tastare puternică” în alte dicționare:

    Tipul de date este un concept fundamental în teoria programării. Un tip de date definește un set de valori, un set de operații care pot fi aplicate acelor valori și, eventual, o modalitate de a implementa stocarea valorilor și efectuarea operațiilor. Oricare... ... Wikipedia

    Tastarea datelor Siguranța tipului Inferența tipului Tastarea dinamică Tastarea statică Tastarea puternică Tastarea moale Tipuri dependente Tastarea tip rață Articol principal: Tastarea puternică Tastarea dinamică este o tehnică pe scară largă... ... Wikipedia

    Tastarea datelor Siguranța tipului Inferența tipului Tastarea dinamică Tastarea statică Tastarea puternică Tastarea moale Tipuri dependente Tastarea tip rață Articol principal: Tastarea puternică Tastarea statică este o tehnică pe scară largă... ... Wikipedia

    Tastarea dinamică este o tehnică utilizată pe scară largă în limbajele de programare și limbajele de specificare, în care o variabilă este asociată cu un tip în momentul atribuirii unei valori, și nu în momentul declarării variabilei. Astfel, în diverse domenii... Wikipedia

    Tastarea datelor Siguranța tipului Inferența tipului Tastarea dinamică Tastarea statică Tastarea puternică Tastarea moale Tipuri dependente Tastarea tipului Inferența tipului în programare este o caracteristică a compilatorului... ... Wikipedia

    Tastare de date Siguranță tip Inferență de tip Tastare dinamică Tastare statică Tastare puternică Tastare soft Tipuri dependente Tastare de rață Tip dependent, în informatică și logică, un tip care depinde de o valoare. Dependenți... ... Wikipedia

    - (se regăsește și termenul tip de date) este un concept fundamental al teoriei programării. Un tip de date definește un set de valori, un set de operații care pot fi aplicate unor astfel de valori și, eventual, o modalitate de a implementa stocarea valorilor și... ... Wikipedia

    Tip de date Cuprins 1 Istoric 2 Definiție 3 Necesitatea de a utiliza tipuri de date ... Wikipedia

    Acest termen are alte semnificații, vezi ML (sensuri). ML Semantică: multi-paradigmă: funcțional, imperativ, modular Apărut în: 1973 Autor(i): Robin Milner și colab. Universitatea din Edinburgh ... Wikipedia