Versiune scurtă
Limbajele de programare prin tastare sunt împărțite în două tabere mari - tipărite și netupate (netăiate). Primul exemplu este C, Python, Scala, PHP și Lua, și al doilea limbaj de asamblare, Forth și Brainfuck.
- Încărcare statică / dinamică. Staticul este determinat de faptul că tipurile finale de variabile și funcții sunt stabilite în etapa de compilare. Ie deja compilatorul este 100% sigur care tip este unde. În tastarea dinamică, toate tipurile se găsesc deja la momentul executării.
Cu toate acestea, nu există limbi cu greșeli statice și dinamice în același timp. Deși am alergat înainte, voi spune că aici minte - există într-adevăr, dar mai mult despre asta mai târziu.
Versiune detaliată
Dacă versiunea scurtă nu pare a fi suficient de bună. Nu în zadar am scris detaliat? Principalul lucru este că în versiunea scurtă a fost pur și simplu imposibil să se potrivească toate informațiile utile și interesante, iar informațiile detaliate vor fi probabil prea lungi pentru ca toată lumea să o citească fără a se încurca.
Nu a fost scrisă
În limbile de programare nedotate - toate entitățile sunt considerate pur și simplu secvențe de biți de diferite lungimi.
Tastarea neautorizată este, de obicei, inerentă în limbile de nivel scăzut (limbaj assembler, Forth) și esoteric (Brainfuck, HQ9, Piet). Cu toate acestea, ea, împreună cu neajunsurile, are anumite avantaje.
avantaje
- Vă permite să scrieți la cel mai mic nivel posibil, iar compilatorul / interpretul nu va interfera cu verificările de tip. Sunteți liber să efectuați orice operațiune pe orice tip de date.
- Codul rezultat este de obicei mai eficient.
- Transparența instrucțiunilor. Dacă cunoașteți limba, nu există nici o îndoială cu privire la ceea ce reprezintă acest cod.
deficiențe
- Complexitatea. Deseori, este necesar să se reprezinte valori complexe, cum ar fi liste, șiruri sau structuri. Acest lucru poate cauza neplăceri.
- Lipsa controalelor. Orice acțiune fără sens, de exemplu scăderea unui indicator la o matrice de la un simbol, va fi considerată perfect normală, care 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.
Tip de tastare greu de tip?
Da, există. De exemplu, în limba de asamblare (pentru arhitectura x86 / x86-64, nu cunosc ceilalți), nu puteți asambla programul dacă încercați să încărcați datele în registrul cx (16 biți) din registrul rax (64 biți).
mov cx, eax; eroare de timp de asamblare
Deci, se pare că în Assemler există încă tastarea? Cred că aceste controale nu sunt suficiente. Și părerea ta, desigur, depinde doar de tine.
Încrucișarea statică și dinamică
Principalul lucru care distinge între tastarea statică (statică) și dinamică (dinamică) este că toate verificările de tip sunt efectuate în etapa de compilare și nu în faza de execuție.
Pentru unii oameni, se poate părea că tastarea statică este prea limitată (de fapt este, dar aceasta a fost mult timp eliminată cu ajutorul unor tehnici). Pentru unii, că limbile dinamice scrise sunt un joc cu foc, dar ce caracteristici le disting? Ambele specii au o șansă de existență? Dacă nu, de ce multe limbi statice și dinamice au fost tipărite?
Beneficiile tipăririi statice
- Verificările de tip apar doar o singură dată - în etapa de compilare. Și aceasta înseamnă că nu va trebui să aflăm în mod constant dacă încercăm să împărțim un număr într-un șir (și fie să emită o eroare sau să efectuăm o conversie).
- Viteza execuției. Din punctul anterior, este clar că limbile statice tipărite sunt aproape întotdeauna mai rapide decât limbile dinamice tipărite.
- În anumite condiții suplimentare, vă permite să detectați eventualele erori deja în etapa de compilare.
Avantajele tastării dinamice
- Simplitatea creării colecțiilor universale - grămezi de toate și toate (rareori există o astfel de necesitate, dar atunci când există o tipificare dinamică va câștiga).
- Comoditatea de a descrie algoritmi generalizați (de exemplu, sortarea unui matrice care va funcționa nu numai pe lista de numere întregi, ci și pe lista numerelor reale și chiar pe lista de rânduri).
- Ușor de învățat - limbile cu tastare dinamică sunt de obicei foarte bune pentru a începe programarea.
Programare generalizată
Ei bine, argumentul cel mai important pentru tastarea dinamică este comoditatea de a descrie algoritmi generalizați. Să ne imaginăm problema - avem nevoie de o funcție pentru a căuta prin mai multe tablouri (sau liste) - printr-o serie de numere întregi, printr-o serie de numere reale și printr-o serie de caractere.
Cum o vom rezolva? Rezolvăm acest lucru în 3 limbi diferite: una cu tastare dinamică și două cu statică.
Algoritmul de căutare Voi lua una dintre cele mai simple - bust. Funcția va prelua elementul, matricea (sau lista) și va returna indexul elementului sau, dacă elementul nu este găsit - (-1).
Soluție dinamică (Python):
După cum puteți vedea, totul este simplu și nu există probleme cu faptul că lista poate conține cel puțin numere, chiar liste, deși nu există alte matrice. Foarte bine. Să mergem mai departe - vom rezolva aceeași sarcină în Si!
Soluție statică (C):
Ei bine, fiecare funcție este asemănătoare cu versiunea Python, dar de ce există trei? A pierdut programarea statică?
Și da, și nu. Există mai multe tehnici de programare, dintre care vom lua în considerare acum. Se numește programare generală, iar limba C ++ o susține bine. Să aruncăm o privire la noua versiune:
Soluție statică (programare generală, C ++):
Bine! Acest lucru nu pare mult mai complicat decât versiunea Python și nu trebuie să scrie prea mult. În plus, avem o implementare pentru toate rețelele, și nu doar pentru 3, necesare pentru rezolvarea problemei!
Această versiune pare să fie exact ceea ce aveți nevoie - obținem atât avantajele tipăririi statice, cât și unele avantaje ale tastării dinamice.
Este minunat că acest lucru este în general posibil, dar poate fi chiar mai bun. În primul rând, programarea generală poate fi mai convenabilă și mai frumoasă (de exemplu, în limba Haskell). În al doilea rând, pe lângă programarea generală, puteți aplica polimorfismul (rezultatul va fi mai rău), funcțiile de supraîncărcare (în mod similar) sau macrocomenzile.
Statică în dinamică
De asemenea, trebuie menționat faptul că multe limbi statice permit utilizarea de tipărire dinamică, de exemplu:
- C # acceptă dinamicul de tip pseudo.
- F # acceptă zahăr sintactic sub forma unui operator. pe baza căruia poate fi implementată o imitație de tipificare dinamică.
- Haskell - tastarea dinamică este furnizată de modulul Data.Dynamic.
- Delphi - prin intermediul unui varianta de tip special.
De asemenea, unele limbi tipizate dinamic vă permit să profitați de scrierea statică:
- Declarații de tip comun Lisp.
- Perl este de la versiunea 5.6, destul de limitat.
Deci, mergem mai departe?
Tiparerea puternică și slabă
Limbile cu tastare puternică nu vă permit să amestecați entități de diferite tipuri în expresii și nu efectuați conversii automate. De asemenea, ele sunt numite "limbi cu tastare strictă". Termenul englezesc pentru aceasta este o tastare puternică.
Tipurile de limbaj slab tipărite, dimpotrivă, contribuie în orice mod la programatorul care amestecă diferite tipuri într-o singură expresie, iar compilatorul însuși va conduce totul la un singur tip. De asemenea, ele sunt numite "limbi cu tastare non-strictă". Termenul englezesc pentru aceasta este tastarea slabă.
Formarea slabă este deseori confundată cu dinamica, ceea ce este complet greșit. O limbă introdusă dinamic poate fi slabă și puternic introdusă.
Cu toate acestea, puțini oameni acordă importanță rigurozității introducerii textului. Se spune adesea că dacă o limbă este tipărită static, atunci veți putea prinde multe erori potențiale la compilare. Te mint pe tine!
Limba trebuie să aibă, de asemenea, o tastare puternică. Și este adevărat că, dacă compilatorul în loc de mesajul de eroare adaugă pur și simplu un rând la un număr sau, mai rău, scade dintr-un alt tablou, care este folosirea pentru noi, că toate "verificările" tipurilor vor fi la etapa de compilare? Așa - tastarea slabă statică este chiar mai rea decât o tastare dinamică puternică! (Ei bine, aceasta este opinia mea)
Deci, tastarea slabă nu are deloc avantaje? Poate așa arăta, dar, în ciuda faptului că sunt un susținător puternic al tastării puternice, trebuie să fiu de acord că cel slab are și avantaje.
Vrei să știi ce?
Avantajele tiparului puternic
- Fiabilitate - primiți o excepție sau o eroare de compilare, în loc de comportament greșit.
- Viteza - în loc de transformări ascunse, care pot fi destul de scumpe, cu tastare puternică, trebuie să le scrieți în mod explicit, ceea ce face cel puțin să știe că acest cod de cod poate fi lent.
- Înțelegerea activității programului - din nou, în loc de turnarea implicită a tipurilor, programatorul scrie totul el însuși și, prin urmare, înțelege foarte mult că compararea liniei și a numărului nu se întâmplă de la sine și nu în magie.
- Cu siguranță - când scrieți conversiile manual, știi exact ce convertiți și în ce. De asemenea, veți înțelege întotdeauna că astfel de transformări pot duce la pierderea preciziei și rezultate incorecte.
Avantajele tastării slabe
- Convenabilitatea utilizării expresiilor mixte (de exemplu, din întregi și numere reale).
- Abstractarea de la tastarea și concentrarea asupra sarcinii.
- Brevetarea înregistrării.
Bine, am rezolvat-o, se pare că tastarea slabă are și avantaje! Și există modalități de a transfera avantajele slabei tastări la puternice?
Se pare că există chiar și două.
Conversie de tip implicită, în situații cu valoare unică și fără pierderi de date
Ugh ... E un punct destul de lung. Permiteți-mi să o reduc și mai mult la o "conversie implicită limitată" Deci, ce este exact o situație lipsită de ambiguitate și o pierdere de date?
O situație unică, aceasta este o transformare sau o operațiune în care esența este ușor de înțeles. De exemplu, adăugarea a două numere este o situație neechivocă. Și convertirea unui număr într-o matrice nu este (este posibil să se creeze un matrice dintr-un element, poate un matrice cu o lungime lungă, umplută cu elemente implicite și poate un număr să fie convertit într-un șir și apoi într-o serie de caractere).
Pierderea datelor este chiar mai ușoară. Dacă convertim un număr real de 3.5 într-un număr întreg, vom pierde câteva date (de fapt, această operație este de asemenea ambiguă - cum va fi efectuată rotunjirea? În ce privește partea mai mare? Pentru a redirecționa partea fracționată?).
Transformările în situații ambigue și transformările cu pierderi de date sunt foarte, foarte rele. Nimic mai rău în programare.
Dacă nu mă credeți, învățați limba PL / I sau chiar căutați specificația sa. Are reguli pentru conversia între TOATE tipurile de date! Doar naibii!
Bine, să ne amintim de o conversie implicită limitată. Există astfel de limbi? Da, de exemplu, în Pascal puteți converti un număr întreg la un număr real, dar nu invers. De asemenea, există mecanisme similare în C #, Groovy și Common Lisp.
Bine, am spus că există și un alt mod de a obține câteva idei de scriere slabă într-o limbă puternică. Și da, se numește polimorfism constructor.
O voi explica cu exemplul minunatului limbaj Haskell.
Constructorii constructori polimorfici au apărut ca urmare a observării faptului că sunt necesare conversii implicite în condiții de siguranță, în condiții de siguranță, atunci când se utilizează literali numerici.
De exemplu, în expresia pi + 1. Nu vreau să scriu pi + 1.0 sau pi + float (1). Vreau să scriu doar pi + 1.
Și acest lucru se face în Haskell, datorită faptului că literalul 1 nu are un tip specific. Nu este nici intreg, nici material, nici complex. E doar un număr!
Ca urmare, atunci când scriem o sumă simplă a funcției x y. Înmulțește toate numerele între x și y (în trepte de 1), vom obține mai multe versiuni - sumă pentru întreg, pentru suma reală, suma pentru rațională, suma pentru numere complexe, chiar și suma tuturor tipurilor numerice pe care le definiți.
Desigur, această metodă este salvată numai atunci când se utilizează expresii mixte cu litere numerice, iar acesta este doar vârful aisbergului.
Bine, vom continua?
Tastarea explicită și implicită
O limbă cu tastare explicită presupune că programatorul trebuie să specifice tipurile de toate variabilele și funcțiile pe care le declară. Termenul englezesc pentru aceasta este tastarea explicită.
O limbă cu scriere implicită, pe de altă parte, sugerează că uitați de tipuri și transferați sarcina de inferență de tip la un compilator sau interpret. Termenul englezesc pentru aceasta este tastarea implicită.
La început, puteți decide că scrierea implicită este echivalentă cu tastarea dinamică și explicită - statică, dar vom vedea mai târziu că nu este cazul.
Există avantaje pentru fiecare specie și, din nou, există combinații între acestea și dacă există limbi cu suport pentru ambele metode?
Avantajele tastării explicite
- Prezența fiecărei funcții de semnătură (de exemplu, int add (int, int)) face posibilă determinarea fără probleme a funcției.
- Programatorul scrie imediat ce tipuri de valori pot fi stocate într-o anumită variabilă, ceea ce elimină necesitatea de a-și aminti.
Avantaje ale tastării implicite
- Reducerea intrării - add add (x, y) este cu mult mai mică decât int add (int x, int y).
- Rezistența la schimbare. De exemplu, dacă într-o funcție o variabilă temporară era de același tip ca și argumentul de intrare, atunci într-o limbă scrisă în mod explicit, schimbarea tipului argumentului de intrare va trebui de asemenea să schimbe tipul variabilei temporare.
Ei bine, este clar că ambele abordări au atât avantaje cât și dezavantaje (și care a așteptat ceva încă?), Deci să căutăm modalități de a combina aceste două abordări!
Tastarea explicită pentru alegere
Există limbi cu tastare implicită în mod implicit și abilitatea de a specifica tipul de valori, dacă este necesar. Traducătorul va tipări automat acest tip de expresie. O astfel de limbă este Haskell, să dăm un exemplu simplu, pentru claritate:
Notă: intenționez să folosesc o funcție necumpată și intenționează, de asemenea, să scriu o semnătură privată în locul unei adăugări mai generale. (Num a) -> a -> a -> a. deoarece Am vrut să arăt ideea, fără a explica sintaxa lui Haskell.
Hmm. După cum vedem, este foarte frumoasă și scurtă. Înregistrarea funcției are doar 18 caractere pe o singură linie, inclusiv spații!
Totuși, ieșirea automată este un lucru destul de complicat, și chiar într-un limbaj atât de abrupt ca Haskell, uneori eșuează. (un exemplu de care este restricția unui monomorfism)
Există limbi cu tastare implicită explicită și implicită - dacă este necesar? joc
echno.
Tastarea implicită prin alegere
Noul limbaj standard de C ++ numit C ++ 11 (denumite anterior C ++ 0x), a fost introdus cuvântul cheie auto, prin care puteți forța compilator pentru a deduce tipul bazată pe context:
Nu-i rău. Dar înregistrarea nu a fost redusă mult. Să ne uităm la exemplu cu iteratori (dacă nu înțelegeți, nu vă temeți, principalul lucru este că înregistrarea datorată producției automate este mult redusă):
Wow! Iată reducerea. Bine, dar este posibil să faci ceva în spiritul lui Haskell, unde tipul valorii returnate va depinde de tipurile de argumente?
Și din nou, răspunsul este da, datorită cuvântului cheie decltype în combinație cu auto:
Se poate părea că această formă de scriere nu este foarte bun, dar în combinație cu programarea generică (templates / generice) tipizarea implicite sau inferenta automată poate face minuni.
Unele limbi de programare pentru această clasificare