Sari la conținut

Tip de date

De la Wikipedia, enciclopedia liberă
Ierarhia standard de tipuri din Python 3

În informatică și programarea calculatoarelor, un tip de date (sau doar tip) este o colecție sau o grupare de valori ale datelor⁠(d), de regulă specificate printr-un set de valori posibile, un set de operațiuni permise asupra acelor valori, și/sau o reprezentare a acestor valori ca tipuri mașină.[1] Specificarea unui tip de date într-un program constrânge valorile posibile pe care le poate lua o expresie⁠(d), cum ar fi o variabilă sau un apel de funcție. Pe datele literale, el spune compilatorului sau interpretorului cum intenționează programatorul să folosească datele. Cele mai multe limbaje de programare suportă ca tipuri de date de bază numerele întregi⁠(d) (de diferite dimensiuni), numere în virgulă mobilă (care aproximează numerele reale), caracterele și booleenii.[2][3]

Există mai multe motive pentru care s-ar dori specificarea unui tip de date: similitudine, convenabilitate, sau dorința de a atrage atenția. Frecvent, este o chestiune de bună organizare, care ajută la înțelegerea definițiilor complexe. Aproape toate limbajele de programare includ explicit noțiunea de tip de date, deși tipurile posibile sunt adesea restricționate din considerente de simplitate, calculabilitate, sau regularitate. Declararea explicită a unui tip de date permite de regulă compilatorului să aleagă o reprezentare mașină eficientă, dar joacă un rol și organizarea conceptuală oferită de tipurile de date.[4]

Diferite limbaje pot folosi tipuri date cu semantici diferite. De exemplu, în limbajul Python, int reprezintă un întreg de precizie arbitrară⁠(d) pe care se pot efectua operații numerice tradiționale, ca adunare, scădere și înmulțire. În limbajul Java, în schimb tipul int reprezintă mulțimea numerelor întregi⁠(d) pe 32 de biți cu valori de la −2.147.483.648 până la 2.147.483.647, cu operațiuni aritmetice care ciclează la overflow⁠(d). În Rust, acest tip de întregi pe 32 de biți se notează cu i32 și dă eroare la overflow în modul debug.[5]

Cele mai multe limbaje de programare permit programatorului și să definească tipuri adiționale, de regulă prin combinarea mai multor elemente de alte tipuri și prin definirea operațiunilor valide asupra noului tip de date. De exemplu, un programator ar putea crea un tip numit „număr complex” care ar include partea reală și cea imaginară; sau un tip de date „culoare” care să reprezinte cei trei octeți care reprezintă cantitățile de roșu, verde și albastru, precum și, eventual, o reprezentare ca șir de caractere al numelui culorii.

Tipurile de date se folosesc în cadrul sistemelor de tipuri⁠(d), care oferă diferite moduri de definire, implementare și utilizare a lor. Într-un sistem de tipuri, un tip de date reprezintă o constrângere aplicată interpretării datelor, descrierii reprezentării, interpretării și structurii valorilor⁠(d) sau obiectelor stocate în memoria calculatorului. Sistemul de tipuri utilizează informația despre tipul de date pentru a verifica corectitudinea programelor de calculator⁠(d) care accesează sau manipulează datele. Un compilator ar putea folosi tipul static al unei valori pentru a optimiza spațiul de stocare necesar sau pentru a alege algoritmii care operează asupra valorii. În multe compilatoare de C, tipul de date float, de exemplu, este reprezentat pe 32 de biți, în conformitate cu specificația IEEE pentru numere în virgulă mobilă cu precizie simplă. Astfel, pe aceste valori, ele vor folosi operațiuni de microprocesor⁠(d) specifice reprezentării în virgulă mobilă (adunare, înmulțire în virgulă mobilă etc.).

Parnas, Shore & Weiss (1976) au identificat cinci definiții ale unui „tip” care au fost folosite—uneori implicit—în literatura de specialitate:

Sintactică
Un tip este o etichetă pur sintactică asociată cu o variabilă⁠(d) la declararea ei. Deși este utilă pentru sistemele avansate de tipuri, cum ar fi sistemele de tipuri substructurale⁠(d), asemenea definiții nu le dau niciun sens intuitiv.
Reprezentare
Un tip este definit în termeni de compunere a mai multor tipuri primitive—adesea, tipuri mașină.
Reprezentare și comportament
Un tip este definit prin reprezentarea sa și printr-un set de operatori⁠(d) ce manipulează acele reprezentări.
Spațiul valorilor
Un tip este o mulțime de valori posibile pe care le poate lua o variabilă. Prin asemenea definiții se poate vorbi despre reuniuni (disjuncte⁠(d)) sau produse carteziene ale tipurilor.
Spațiul valorilor și comportament
Un tip este un set de valori pe care le poate lua o variabilă, și un set de funcții⁠(d) care se poat aplica pe aceste valori.

Definiția în termeni de reprezentare se face adesea în limbaje imperative, ca ALGOL și Pascal, în timp ce definiția în termeni de spațiu al valorilor și comportament este folosită în limbaje de nivel mai înalt, ca Simula și CLU⁠(d). Tipurile care cuprind și comportamentul se aliniază mai îndeaproape cu modelele orientate pe obiecte, în vreme ce un model pentru programarea structurată ar tinde să nu includă cod, asemenea modele fiind denumite structuri de date pasive⁠(d).

Tipurile de date pot fi categorisite după mai mulți factori:

  • Tipurile de date primitive⁠(d) sunt cele incluse într-o implementare a limbajului. Tipurile definite de utilizator nu sunt primitive. De exemplu, tipurile numerice din Java sunt primitive, dar clasele sunt definite de utilizator.
  • O valoare a unui tip atomic este un element unic de date care nu poate fi descompus în părți componente. O valoare a unui tip compozit⁠(d) sau agregat este o colecție de elemente de date ce pot fi accesate individual.[6] De exemplu, un întreg este în general considerat atomic, deși constă dintr-un șir de biți, dar un tablou de numere întregi este cu certitudine compozit.
  • Tipurile de date de bază sau fundamentale sunt definite axiomatic din noțiuni fundamentale, sau prin enumerarea elementelor lor. Tipurile de date derivate sunt specificate, și în parte definite, în termeni de alte tipuri de date. Toate tipurile de bază sunt atomice. De exemplu, întregii sunt un tip de bază definit în matematică, dar un tablou de întregi este rezultatul aplicării unui generator de tip tablou asupra tipului întreg.

Terminologia variază – în literatură, denumirile de tip primitiv, de bază, atomic și fundamental pot fi folosite pentru aceeași noțiune.[7]

Tipuri de date mașină

[modificare | modificare sursă]

La cel mai scăzut nivel, toate datele din calculatoarele bazate pe electronică digitală sunt reprezentate ca biți (ce pot avea valori de 0 și 1). Cea mai mică unitate de date adresabilă este numită byte (de regulă un octet, adică 8 biți). Unitatea prelucrată de instrucțiunile de cod mașină se numește cuvânt⁠(d) (în 2026, aceasta însemna de regulă 64 de biți).

Tipurile de date mașină expun (sau pun la dispoziție) un control fin asupra hardware-ului, dar și detalii de implementare care pot face codul să fie mai puțin portabil. Astfel, tipurile mașină sunt folosite mai ales în programarea de sistem⁠(d) sau în limbajele de programare de nivel scăzut⁠(d). În limbajele de nivel mai înalt, cele mai multe tipuri de date sunt abstractizate prin aceea că nu au o reprezentare mașină definită de limbaj. Limbajul C, de exemplu, furnizează tipuri ca booleeni, întregi, numere în virgulă mobilă etc., dar reprezentările exacte pe biți ale acestor tipuri sunt definite de implementare. Singurul tip C cu o reprezentare mașină exactă este tipul char ce reprezintă un octet.[8]

Tipul boolean

[modificare | modificare sursă]

Tipul boolean reprezintă valorile adevărat⁠(d) și fals⁠(d). Deși sunt posibile doar două valori, ele sunt cel mai adesea reprezentate pe un octet sau un cuvânt, și nu pe un singur bit, întrucât este nevoie de mai multe operații mașină pentru a stoca și adresa un bit individual. Multe limbaje de programare nu au un tip boolean explicit, folosind în schimb un tip întreg în care interpretează valoarea (de exemplu) 0 ca fals și celelalte valori ca adevărat. Datele booleene se referă la structura logică a felului cum se interpretează lumbajul în cod mașină. În acest caz, un 0 boolean reprezintă un fals logic. Adevărul este întotdeauna diferit de zero, adică un 1 boolean.

Aproape toate limbajele de programare furnizează unul sau mai multe tipuri de date întregi⁠(d). Ele pot furniza fie un număr mic de subtipuri predefinite restricționate la anumite intervale (cum ar fi short și long cu variantele lor unsigned corespunzătoare în C/C++); sau pot permite utilizatorilor să definească în mod liber subintervale ca 1..12 (de ex., Pascal/Ada). Dacă nu există un tip nativ corespunzător pe platforma de rulare, compilatorul le va descompune în cod folosind tipuri care există. De exemplu, dacă un număr întreg pe 32 de biți este cerut de un program compilat pe o platformă pe 16 biți, compilatorul îl va trata tacit ca un tablou de doi întregi pe 16 biți.

Datele în virgulă mobilă reprezintă anumite valori fracționare (din punct de vedere matematic, numere raționale). Deși au limite predefinite asupra valorilor maxime și asupra preciziei lor, ele sunt adesea denumite în mod eronat „numere reale” (care evocă numerele reale din matematică). Intern, ele sunt de regulă stocate sub forma a × 2b (cu a și b întregi, denumiți mantisă și exponent), dar se afișează și în formă zecimală.

Datele în virgulă fixă sunt convenabile pentru valori monetare. Ele sunt adesea stocate intern ca numere întregi, cu limitele predefinite.

Pentru independența de detaliile arhitecturii, se pot furniza și tipuri de date Bignum sau de precizie arbitrară⁠(d). Acestea reprezintă un număr întreg sau rațional la o precizie limitată doar de memoria disponibilă și de resursele computaționale ale sistemului. Implementările operațiilor aritmetice pe asemenea tipuri de date sunt semnificativ mai lente decât operațiile mașină corespunzătoare.[9]

Tipurule enumerate⁠(d) au valori distincte, care pot fi comparate și atribuite, dar care nu au neapărat vreo reprezentare concretă în memoria calculatorului; compilatoarele și interpretoarele le pot reprezenta arbitrar. De exemplu, cele patru culori ale cărților de joc pot fi patru enumeratori numiți TREFLĂ, CARO, CUPĂ, PICĂ, aparținând unui tip enumerat CuloareCărți. Dacă se declară o valoare V de acest tip, ei i se pot atribui oricare din aceste patru valori. Unele implementări le permit programatorilor să atribuie valori numerice valorilor enumerate, sau chiar să le trateze ca tipuri echivalente cu întregii.

Tipurile text sau șir de caractere

[modificare | modificare sursă]

Șirurile de caractere⁠(d) sunt o secvență de caractere folosite pentru a stoca cuvinte sau text simplu, cel mai adesea limbaje de markup textuale ce reprezintă text formatat. Caracterele pot fi litere din vreun alfabet, cifre, spații, semne de punctuație etc. Caracterele sunt extrase dintr-un set de caractere cum ar fi ASCII sau Unicode. Caracterele și alte tipuri similare pot avea subtipuri diferite conform codificării caracterelor. Setul originar ASCII pe 7 biți și-a atins rapid limitele, și a fost înlocuit cu seturi de caractere pe 8, 16 și 32 de biți, care pot codifica o varietate mare de alfabete nelatine (cum ar fi cel ebraic și cel chinezesc) și alte simboluri. Șirurile de caractere pot fi de lungime fixă sau variabilă, iar unele limbaje le suportă pe ambele.

Întrucât cele mai multe seturi de caractere cuprind și cifrele, poate fi reprezentat și un șir numeric, cum ar fi "1234". Aceste șiruri numerice sunt de regulă considerate distincte de valorile numerice ca 1234, dar unele limbaje convertesc automat între ele. Ca exemplu, limbajul ECMAScript are operatori diferiți de comparație care dau rezultate diferite când se compară valoarea numerică cu cea textuală a unui număr.

Tipurile reuniune

[modificare | modificare sursă]

Definiția unui tip reuniune specifică ce subtipuri dintr-un număr de subtipuri permise pot fi stocate în instanțele sale, de exemplu „virgulă mobilă sau întreg lung”. Spre deosebire de înregistrare⁠(d), care poate fi definit ca a conține un număr în virgulă mobilă și un întreg, reuniunea poate conține doar un subtip.

O reuniune cu etichetă⁠(d) (denumit variant, înregistrare varianță, reuniune discriminată, sau reuniune disjunctă) conține încă un câmp care indică tipul actual pentru siguranța operațiunilor.

Tipuri de date algebrice

[modificare | modificare sursă]

Un tip de date algebric⁠(d) (ADT, algebraic data type) este un tip sumă⁠(d), posibil recursiv, de tipuri produs⁠(d). O valoare a unui ADT constă dintr-o etichetă constructor împreună cu zero sau mai multe valori ale câmpurilor, numărul și tipul valorilor câmpurilor fiind fixat de către constructor. Mulțimea tuturor valorilor posibile ale unui ADT este reuniunea disjunctă (din teoria mulțimilor) a mulțimilor tuturor valorilor posibile ale variantelor (produsul câmpurilor). Valorile tipurilor algebrice se analizează prin identificarea șabloanelor, prin care se găsește valoarea constructorului și se extrag câmpurile pe care el le conține.

Dacă există un singur constructor, atunci ADT corespunde unui tip produs similar unui tuplu sau unei înregistrări. Un constructor fără câmpuri corespunde produsului vid (tipul unitate). Dacă niciun constructor nu are câmpuri, atunci ADT corespunde unui tip enumerat⁠(d).

Un ADT frecvent întâlnit este tipul opțiune⁠(d), definit în Haskell ca data Maybe a = Nothing | Just a.[10]

Structuri de date

[modificare | modificare sursă]

Unele tipuri sunt foarte utile pentru stocarea și accesarea datelor și sunt numite structuri de date. Exemple de structuri de date sunt:

  • Tabloul⁠(d) (denumit și vector, listă⁠(d), sau șir) stochează mai multe elemente și furnizează acces aleator la elementele individuale. Elementele unui tablou sunt, de regulă (dar nu întotdeauna) de același tip. Tablourile pot fi de lungime fixă sau extensibile. Indicii din tablou sunt de regulă întregi (dacă nu se impune regula, această relaxare se poate susține discutând despre un tablou asociativ⁠(d)) dintr-un interval anume (dacă nu toți indicii din interval corespund unor elemente, tabloul este dispersat).
  • Înregistrarea⁠(d) (denumită și tuplu sau struct) este una dintre cele mai simple structuri de date, a cărei valoare conține alte valori, de regulă în număr și secvență fixate, și indexate după nume. Elementele înregistrărilor se numesc câmpuri sau membri, și pot avea orice alt tip.
  • Un obiect conține mai multe câmpuri de date, la fel ca o înregistrare, dar conține și mai multe subrutine pentru accesarea sau modificarea lor.
  • Lista simplu înlănțuită⁠(d), care poate fi folosită pentru a implementa o coadă⁠(d) și este definită în Haskell ca ADT data List a = Nil | Cons a (List a)
  • Arborele binar, care permite căutarea rapidă, și poate fi definit în Haskell ca ADT data BTree a = Nil | Node (BTree a) a (BTree a)[11]

Tipuri de date abstracte

[modificare | modificare sursă]

Un tip de date abstract⁠(d) este un tip de date ce nu specifică o reprezentare concretă a datelor. Pentru a-l descrie, se folosește o specificație formală bazată pe operațiile asupra tipului de date. Orice implementare a specificației trebuie să respecte regulile definite în ea. De exemplu, o stivă are operații de push/pop care respectă o regulă Last-In-First-Out, și pot fi implementate concret fie cu o listă, fie cu un tablou. Tipurile de date abstracte se folosesc în semantica⁠(d) formală și în verificarea⁠(d) programelor și, cu mai puțină strictețe, în design.

Pointeri și referințe

[modificare | modificare sursă]

Principalul tip derivat necompozit este pointerul⁠(d), un tip de date ale cărui valori se referă direct la o altă valoare stocată altundeva în memoria calculatorului, folosind adresa⁠(d) ei. Ea este o formă primitivă a referinței⁠(d). (Intuitiv, un număr de pagină dintr-o carte poate fi considerată un astfel de pointer care se referă la alte date – textul din pagină). Pointerii sunt adesea stocați într-un format similar unui întreg; dereferențiere pointerului poate însă duce programul în eroare dacă valoarea nu reprezintă o adresă validă de memorie. Pentru a ameliora această problemă potențială, tipul pointer este considerat de regulă distinct de tipul întreg, chiar dacă reprezentarea folosită pentru el este aceeași.

Tipuri funcție

[modificare | modificare sursă]

Limbajele de programare funcțională tratează funcțiile ca pe un tip distinct de date și permit stocarea acestor tipuri în variabile și transmiterea lor ca parametri altor funcții. Unele limbaje multi-paradigmă, ca JavaScript, au și ele mecanisme de tratare a funcțiilor ca pe date.[12] Cele mai multe sistemuri de tipuri contemporane merg și mai departe decât atât, și au o familie de tipuri funcție diferențiate după tipurile argumentelor și tipul returnat, cum ar fi tipul Int -> Bool ce reprezintă funcții care primesc un număr întreg și returnează un boolean. În C, funcțiile nu sunt date de primă clasă, ci sunt pointeri la funcții⁠(d) ce pot fi manipulați de către program. Java și C++ nu aveau la început funcții ca valori, dar au apărut între timp, la versiunile C++11 și Java 8.

Constructori de tipuri

[modificare | modificare sursă]

Un constructor de tipuri construiește tipuri noi din cele deja existente, și poate fi văzut ca un operator ce primește zero sau mai multe tipuri ca argument și produce un alt tip. Tipurile produs, tipurile funcție, tipurile putere și tipurile listă pot fi constructori de tipuri.

Tipuri cuantificate

[modificare | modificare sursă]

Tipurile universal-cuantificate și existențial-cuantificate se bazează pe logica cu predicate. Cuantificarea universală se scrie ca ∀x.f(x) sau forall x. f x și este intersecția tuturor tipurilor x din corpul f x, adică valoarea este de tip f x pentru orice x. Cuantificarea existențială se scrie ca ∃x.f(x) sau exists x. f x și este reuniunea tuturor tipurilor x din corpul f x, adică valoarea este de tip f x pentru un x.

În Haskell, cuantificarea universală se folosește frecvent, dar tipurile existențiale trebuie codificate transformând exists a. f a într-un forall r. (forall a. f a -> r) -> r sau într-un tip similar.

Tipuri de rafinare

[modificare | modificare sursă]

Un tip de rafinare este un tip dotat cu un predicat care se presupune că este adevărat pentru orice element din tipul rafinat. De exemplu, tipul numerelor naturale mai mari ca 5 se poate scrie ca {n∈ℕ|n>5}

Tipuri dependente

[modificare | modificare sursă]

Un tip dependent este un tip a cărui definiție depinde de o valoare. Două exemple comune sunt funcțiile dependente și perechile dependente. Tipul returnat de o funcție dependentă poate depinde de valoarea (nu doar de tipul) unuia dintre argumente. O pereche dependentă poate avea o a doua valoare al cărui tip depinde de prima valoare.

Tipuri intersecție

[modificare | modificare sursă]

Un tip intersecție este un tip ce conține acele valori care sunt membri a două tipuri specificate. De exemplu, în Java, clasa Boolean implementează interfețele Serializable și Comparable. Astfel, un obiect de tipul Boolean este și membru al tipului Serializable & Comparable. Considerând aceste tipuri ca mulțimi de valori, tipul intersecție σ∩τ este intersecția mulțimilor σ și τ. Este posibil și să se definească un tip intersecție dependent, notat cu (x:σ)∩τ, unde tipul τ poate depinde de variabila x.[13]

Tipuri de conveniență

[modificare | modificare sursă]

Pentru conveniență, unele limbaje și baze de date de nivel înalt pot furniza tipuri de date din „lumea reală”, cum ar fi date calendaristice, timp, sau valori monetare.[14][15] Acestea pot fi incluse în limbaj sau implementate ca tipuri compozite într-o bibliotecă.[16]

  1. ↑ Parnas, Shore & Weiss 1976.
  2. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  3. ↑ Shaffer, C. A. (). Data Structures & Algorithm Analysis in C++ (ed. 3rd). Mineola, NY: Dover. ISBN 978-0-486-48582-9. Parametru necunoscut |la= ignorat (ajutor)
  4. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  5. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  6. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  7. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  8. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  9. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  10. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  11. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  12. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  13. ↑ Kopylov, Alexei (). „Dependent intersection: A new way of defining records in type theory”. 18th IEEE Symposium on Logic in Computer Science. LICS 2003. IEEE Computer Society. pp. 86–95. doi:10.1109/LICS.2003.1210048.
  14. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.
  15. ↑ Shaffer, C. A. (). Data Structures & Algorithm Analysis in C++ (ed. 3rd). Mineola, NY: Dover. ISBN 978-0-486-48582-9. Parametru necunoscut |la= ignorat (ajutor)
  16. ↑ Acest articol a fost bazat original pe informații de la Dicționarul Online Gratuit de Calculatoare.

Lectură suplimentară

[modificare | modificare sursă]

Legături externe

[modificare | modificare sursă]