Tip de date

Un tip de date ( tip ) este un set de valori și operații asupra acestor valori (IEEE Std 1320.2-1998) [1] .

Alte definiții:

Un tip definește valorile posibile și semnificația acestora, operațiile și modul în care sunt stocate valorile tipului. Studiat prin teoria tipurilor . O parte integrantă a majorității limbajelor de programare sunt sistemele de tip , care folosesc tipuri pentru a oferi un anumit grad de siguranță a tipului .

Definiție

Tipul de date caracterizează în același timp:

Prima proprietate poate fi privită ca o definiție teoretică a mulțimilor a noțiunii de tip; a doua este ca o definiție procedurală (sau comportamentală).

În plus, în programare, se folosește o definiție de nivel scăzut a unui tip - ca date caracteristice dimensionale și structurale ale unei celule de memorie, în care poate fi plasată o anumită valoare corespunzătoare acestor caracteristici. O astfel de definiție este un caz special al celui teoretic mulțimilor. În practică, o serie de proprietăți importante sunt asociate cu acesta (datorită particularităților organizării memoriei computerului ), necesitând luare în considerare separată .

Definiția teoretică a mulțimilor, în special în varianta sa de nivel scăzut, este cel mai frecvent utilizată în programarea imperativă . Definiția procedurală este mai mult asociată cu polimorfismul parametric . Programarea orientată pe obiect folosește definiția procedurală atunci când descrie interacțiunea componentelor programului și definiția teoretică a mulțimii atunci când descrie implementarea acestor componente pe un computer, respectiv, luând în considerare „ class-as-behavior ” și „ class-as-object în memorie ”. " .

Operația de atribuire a unui tip entităților informaționale se numește tastare . Verificarea atribuirii și consecvenței tipului se poate face în prealabil ( tastare statică ), direct la utilizare ( tastare dinamică ) sau o combinație a ambelor metode. Tipurile pot fi atribuite „o dată pentru totdeauna” ( dactilografiere puternică ) sau li se poate modifica ( tastare slabă ).

Tipurile evită paradoxul lui Russell , în special, Church a introdus tipuri în calculul lambda tocmai în acest scop [6] .

În limbajul natural, pronumele interogative sunt responsabile de tastarea .

Tratarea uniformă a datelor de diferite tipuri se numește polimorfism [7] [8] .

Conceptul de siguranță de tip se bazează în primul rând pe definirea tipului procedural. De exemplu, o încercare de a împărți un număr cu un șir va fi respinsă de majoritatea limbilor, deoarece nu este definit niciun comportament corespunzător pentru aceste tipuri. Limbile scrise slab tind să fie definiții de nivel scăzut. De exemplu, „ număr ” și „ înregistrare ” au un comportament diferit, dar valoarea adresei „ înregistrare ” din memoria computerului poate avea aceeași reprezentare la nivel scăzut ca „număr”. Limbile scrise slab oferă capacitatea de a sparge sistemul de tipări prin atribuirea unui comportament „ număr ” unei valori printr-o operație de turnare . Astfel de trucuri pot fi folosite pentru a crește eficiența programelor, dar prezintă riscul de blocare și, prin urmare, nu sunt permise în limbi sigure sau sunt strict izolate.

Clasificare

Există diferite clasificări de tipuri și reguli pentru atribuirea lor.

Prin analogie cu matematica, tipurile de date sunt împărțite în scalare ( primitive ) și non- scalare ( agregate ). O valoare de tip non-scalar (o valoare non-scalar) are multe componente vizibile de utilizator, în timp ce o valoare de tip scalar (o valoare scalară) nu are. [9] Exemple de tip non-scalar sunt matrice , liste și așa mai departe; exemple de tip scalar sunt „ întreg ”, „ boolean ”, etc.

Tipurile structurale (agregate) nu trebuie identificate cu structurile de date : unele structuri de date sunt încorporate direct de anumite tipuri structurale, dar altele sunt construite prin compoziția lor, cel mai adesea recursive. În acest din urmă caz, se vorbește de tipuri de date recursive . Un exemplu de structuri de date care sunt aproape întotdeauna construite prin compoziția obiectelor de tip recursiv sunt arborii binari .

Conform unei alte clasificări, tipurile sunt împărțite în independente și dependente . Varietăți importante ale acestora din urmă sunt tipurile de referință , care, la rândul lor, sunt indicatori . Referințele (inclusiv pointerii) sunt un tip dependent non-compozit, ale căror valori sunt adresa din memoria computerului a unei alte valori. De exemplu, în sistemul de tip C , tipul „ pointer la un întreg fără semn ” este scris ca „ unsigned *„ , în limbajul ML , tipul „ referință la un întreg fără semn ” este scris ca „ word ref„ .

Tipurile sunt, de asemenea, împărțite în monomorfe și polimorfe (a se vedea variabila tip ).

Unele tipuri de date comune

Tip boolean

Valorile logice sau booleene (după numele inventatorului lor - Boole), pot avea doar una din două stări - „adevărat” sau „fals”. În diferite limbi, acestea sunt notate boolcu , BOOLsau boolean. „Adevărul” poate fi notat ca true, TRUEsau #T. „Fals”, respectiv false, FALSEsau #F. În C și C++, orice număr diferit de zero este tratat ca adevărat, iar zero este tratat ca fals. În Python , unor tipuri individuale li se atribuie, de asemenea, o valoare „booleană”. În principiu, un bit este suficient pentru a implementa tipul, cu toate acestea, datorită naturii microprocesoarelor, în practică dimensiunea valorilor booleene este de obicei egală cu dimensiunea unui cuvânt de mașină .

Tipuri întregi

Tipurile întregi conțin valori interpretate ca numere (semnate și nesemnate).

Numere în virgulă mobilă

Folosit pentru a reprezenta numere reale (nu neapărat întregi). În acest caz, numărul este scris ca x=a*10^b. Unde 0<=a<1 și b este un număr întreg dintr-un anumit interval. a se numește mantisa, b este ordinul. Mantisa stochează mai multe cifre după punctul zecimal, iar b este stocat în întregime.

Tipuri de șiruri

O secvență de caractere care este tratată ca un întreg în contextul unei variabile. Diferite limbaje de programare impun diferite restricții asupra variabilelor șir. Șirurile pot conține secvențe de escape .

Indicatori

Un pointer este o variabilă al cărei interval de valori constă din adrese de locații de memorie sau o valoare specială pentru a indica faptul că nu este stocat nimic în variabilă.

Tipuri de identificare

Tipurile de identitate nu sunt interpretate ca un număr, ci ca un identificator unic de obiect. De exemplu, FourCC .

Tipuri de date abstracte

Tipuri de date care sunt luate în considerare indiferent de context și implementare într-un anumit limbaj de programare. Abstracția în sens matematic înseamnă că algebra datelor este tratată până la izomorfism . Tipurile abstracte sunt utilizate pe scară largă în metodologia de programare bazată pe dezvoltarea programului pas cu pas. În etapa de construire a specificației programului proiectat, algebra de date modelează obiectele domeniului de studiu, în ceea ce privește problema rezolvată. În procesul de rafinare incrementală, datele sunt concretizate prin trecerea la reprezentări intermediare până când implementarea lor este găsită folosind algebra de date de bază a limbajului de programare utilizat. Există mai multe moduri de a defini tipurile abstracte: algebric, model și axiomatic. În abordarea modelului, elementele de date sunt definite în mod explicit. Abordarea algebrică folosește metode de relații algebrice, în timp ce abordarea axiomatică folosește formalizarea logică.

Exemple

Auto-aplicare

Un tip poate fi parametrizat de un alt tip, în conformitate cu principiile abstractizării și parametricității . De exemplu, pentru a implementa o funcție de sortare a secvențelor, nu este necesar să cunoașteți toate proprietățile elementelor sale constitutive - este necesar doar ca acestea să permită o operație de comparare - și atunci tipul compus „ secvență ” poate fi definit ca polimorf din punct de vedere parametric . . Aceasta înseamnă că componentele sale nu sunt definite folosind tipuri concrete (cum ar fi „ întreg ” sau „ matrice de numere întregi ”), ci parametri de tip. Astfel de parametri sunt numiți variabile de tip ( variabilă de tip engleză  ) - sunt utilizați în definirea unui tip polimorf la fel ca parametrii de valoare într-o definiție a funcției. Înlocuirea tipurilor de beton ca parametri reali pentru un tip polimorf produce un tip monomorf. Astfel, un tip polimorf din punct de vedere parametric este un constructor de tip , adică un operator pe tipuri în aritmetica de tip.

Definirea unei funcții de sortare ca fiind polimorfă din punct de vedere parametric înseamnă că sortează o secvență abstractă, adică o secvență de elemente de un tip (necunoscut). În acest caz, funcția trebuie să cunoască doar două proprietăți despre parametrul său - că este o secvență și că operația de comparare este definită pentru elementele sale . Luarea în considerare a parametrilor într-un mod procedural mai degrabă decât declarativ (adică folosirea lor pe baza comportamentului mai degrabă decât a valorii) vă permite să utilizați o singură funcție de sortare pentru orice secvențe - pentru secvențe de numere întregi, pentru secvențe de șiruri de caractere, pentru secvențe de secvențe de boolean valori și așa mai departe — și crește semnificativ factorul de reutilizare a codului . Tastarea dinamică oferă aceeași flexibilitate , totuși, spre deosebire de polimorfismul parametric , primul vine cu supraîncărcare. Polimorfismul parametric este cel mai dezvoltat în limbajele tip Hindley-Milner , adică descendenții limbajului ML . În programarea orientată pe obiecte , polimorfismul parametric se numește programare generică .

În ciuda avantajelor evidente ale polimorfismului parametric, uneori devine necesar să se asigure un comportament diferit pentru diferite subtipuri de același tip general, sau un comportament similar pentru tipurile incompatibile - adică într-o formă de polimorfism ad-hoc . Cu toate acestea, nu există o bază matematică pentru aceasta, așa că cerințele de siguranță de tip au făcut dificilă utilizarea pentru o lungă perioadă de timp. Polimorfismul ad-hoc a fost implementat în cadrul unui sistem de tip parametric polimorf prin diverse trucuri. În acest scop, s-au folosit fie tipuri de variante , fie module parametrice ( functori sau așa-numitele „ valori indexate de tip ”) care, la rândul lor, au și un număr de implementări [ 10] Clasele de tip ,  introduse în limba Haskell a oferit o soluție mai elegantă la această problemă.

Dacă entitatea informațională în cauză este un tip, atunci alocarea unui tip va duce la conceptul de „ tip de tip ” („ metatip ”). În teoria tipurilor, acest concept este numit „ tip de tipuri ” ( ing.  fel de tip sau tip tip ). De exemplu, genul „ *” include toate tipurile, iar genul „ * -> *” include toți constructorii de tip unari . Genurile sunt utilizate în mod explicit în programarea cu tip complet  , de exemplu, ca constructori de tip în limbaje din familia ML .

Extinderea sistemului sigur de tip polimorf la clase și genuri de tip a făcut din Haskell primul limbaj complet tipizat . Sistemul de tip rezultat a influențat alte limbi (de exemplu , Scala , Agda ).

O formă limitată de metatipuri este, de asemenea, prezentă într-un număr de limbaje orientate pe obiecte sub formă de metaclase . În descendenții limbajului Smalltalk (cum ar fi Python ), fiecare entitate dintr-un program este un obiect care are un tip care este el însuși un obiect - astfel, metatipurile sunt o parte naturală a limbajului. În limbajul C++ , subsistemul RTTI este implementat separat de sistemul de tip principal al limbajului , care oferă, de asemenea, informații de tip sub forma unei structuri speciale.

Elucidarea dinamică a metatipurilor se numește reflecție (și, de asemenea, reflexivitate sau introspecție).

Reprezentare computer

Cea mai vizibilă diferență între programarea reală și teoria informației formale este luarea în considerare a problemelor de eficiență nu numai în ceea ce privește notația O , ci și din punctul de vedere al fezabilității economice a implementării anumitor cerințe într-un computer fabricat fizic . Și, în primul rând, acest lucru afectează precizia permisă a calculelor: conceptul de „număr” dintr-un computer în practică nu este identic cu conceptul de număr din aritmetică . Numărul din computer este reprezentat de o celulă de memorie , a cărei dimensiune este determinată de arhitectura computerului , iar intervalul de valori al numărului este limitat de dimensiunea acestei celule. De exemplu, procesoarele arhitecturii Intel x86 furnizează celule a căror dimensiune în octeți este setată la o putere de doi: 1, 2, 4, 8, 16 etc. Procesoarele din arhitectura Setun oferă celule a căror dimensiune în trăsături este setată la o multiplu de trei: 1, 3, 6, 9 etc.

O încercare de a scrie într-o celulă o valoare care depășește limita maximă permisă pentru aceasta (care este cunoscută ) are ca rezultat o eroare de depășire . Dacă este necesar să se calculeze pe numere mai mari, se folosește o tehnică specială, numită aritmetică lungă , care, din cauza intensității semnificative a resursei, nu poate fi efectuată în timp real. Pentru cele mai comune arhitecturi de computere în prezent, „nativul” este dimensiunea celulei de 32 și 64 de biți (adică 4 și 8 octeți ).

În plus, numerele întregi și reale au reprezentări diferite în aceste celule: numerele întregi nenegative sunt reprezentate direct , numerele întregi negative sunt reprezentate în complement a doi , iar numerele reale sunt codificate într-un mod special . Datorită acestor diferențe, adăugarea numerelor " 1" și " 0.1", care în teorie dă valoarea " 1.1", este direct imposibilă pe un computer. Pentru a-l implementa, trebuie mai întâi să efectuați o conversie de tip , generând o 1nouă valoare de tip real „ ” pe baza valorii tipului întreg „ 1.0” și abia apoi adăugați „ 1.0” și „ 0.1”. Datorită specificului implementării numerelor reale pe un computer, o astfel de transformare nu se realizează în mod absolut exact, ci cu un anumit grad de aproximare. Din același motiv, limbajele puternic tipizate (cum ar fi Standard ML ) tratează tipul real ca tipuri de egalitate (sau tipuri de identitate) ( Equality type ).

Pentru reprezentarea la nivel scăzut a tipurilor compozite, conceptul de aliniere a datelor este important . Limbajele de nivel înalt izolează de obicei (resumează) programatorul de această proprietate, totuși, trebuie luat în considerare atunci când se conectează module compilate independent între ele. Cu toate acestea, unele limbaje ( C - , C ++ ) oferă capacitatea de a controla reprezentarea la nivel scăzut a tipurilor, inclusiv alinierea. Astfel de limbi sunt uneori numite limbi de nivel mediu.

Note

  1. IEEE Std 1320.2-1998 (R2004) IEEE Standard for Conceptual Modeling Language Syntax and Semantics for IDEF1X97:
    un set de valori și operații pe acele valori
  2. ISO/IEC/IEEE 24765-2010 Sisteme și inginerie software - Vocabular Arhivat 17 iunie 2016 la Wayback Machine :
    o clasă de date, caracterizată de membrii clasei și operațiunile care le pot fi aplicate
  3. IEEE Std 1320.2-1998 (R2004) IEEE Standard for Conceptual Modeling Language Syntax and Semantics for IDEF1X97:
    o categorizare a unui set abstract de valori posibile, caracteristici și set de operații pentru un atribut
  4. ISO/IEC 19500-2:2003, Tehnologia informației - Procesare distribuită deschisă - Partea 2: Protocolul general Inter-ORB (GIOP)/Protocolul Internet Inter-ORB (IIOP):
    o clasificare a argumentelor de operare a valorilor, care acoperă de obicei ambele comportament şi reprezentare
  5. C. J. Data . Despre diferențele logice între tipuri, valori și variabile // Data în baza de date: Scrieri 2000-2006, Apress, 2006, ISBN 978-1-59059-746-0
  6. Harrison J. Introduction to Functional Programming  = http://www.cl.cam.ac.uk/Teaching/Lectures/funprog-jrh-1996/ . - 1997. Arhivat la 11 ianuarie 2015.
  7. Strachey, 1967 , 3.6.4. Polimorfismul, p. 36-37.
  8. Cardelli, 1991 , 2. Limbi tipare, p. 5.
  9. Data K.J., 2005 .
  10. Valori indexate tip . Consultat la 15 iulie 2014. Arhivat din original la 21 aprilie 2016.

Literatură