
En informatique et en programmation informatique , un type de données (ou simplement type ) est une collection ou un regroupement de valeurs de données , généralement spécifié par un ensemble de valeurs possibles, un ensemble d'opérations autorisées sur ces valeurs et/ou une représentation de ces valeurs sous forme de types de machines. Une spécification de type de données dans un programme limite les valeurs possibles qu'une expression , telle qu'une variable ou un appel de fonction, peut prendre. Sur les données littérales, elle indique au compilateur ou à l'interpréteur comment le programmeur entend utiliser les données. La plupart des langages de programmation prennent en charge les types de données de base des nombres entiers (de tailles variables), des nombres à virgule flottante (qui se rapprochent des nombres réels ), des caractères et des booléens .
Concept
Un type de données peut être spécifié pour de nombreuses raisons : similarité, commodité ou pour attirer l'attention. Il s'agit souvent d'une question de bonne organisation qui aide à la compréhension de définitions complexes. Presque tous les langages de programmation incluent explicitement la notion de type de données, bien que les types de données possibles soient souvent limités par des considérations de simplicité, de calculabilité ou de régularité. Une déclaration explicite de type de données permet généralement au compilateur de choisir une représentation machine efficace, mais l'organisation conceptuelle offerte par les types de données ne doit pas être négligée.
Différents langages peuvent utiliser différents types de données ou des types similaires avec une sémantique différente. Par exemple, dans le langage de programmation Python , intreprésente un entier de précision arbitraire qui comporte les opérations numériques traditionnelles telles que l'addition, la soustraction et la multiplication. Cependant, dans le langage de programmation Java , le type intreprésente l'ensemble des entiers 32 bits dont la valeur est comprise entre −2 147 483 648 et 2 147 483 647, avec des opérations arithmétiques qui s'enroulent en cas de dépassement . Dans Rust, ce type d'entier 32 bits est noté et panique en cas de dépassement en mode débogage. i32
La plupart des langages de programmation permettent également au programmeur de définir des types de données supplémentaires, généralement en combinant plusieurs éléments d'autres types et en définissant les opérations valides du nouveau type de données. Par exemple, un programmeur peut créer un nouveau type de données appelé « nombre complexe » qui comprendrait des parties réelles et imaginaires, ou un type de données de couleur représenté par trois octets indiquant les quantités de rouge, de vert et de bleu, et une chaîne représentant le nom de la couleur.
Les types de données sont utilisés dans les systèmes de types , qui offrent différentes manières de les définir, de les implémenter et de les utiliser. Dans un système de types, un type de données représente une contrainte placée sur l'interprétation des données, décrivant la représentation, l'interprétation et la structure des valeurs ou des objets stockés dans la mémoire de l'ordinateur. Le système de types utilise les informations de type de données pour vérifier l'exactitude des programmes informatiques qui accèdent aux données ou les manipulent. Un compilateur peut utiliser le type statique d'une valeur pour optimiser le stockage dont il a besoin et le choix des algorithmes pour les opérations sur la valeur. Dans de nombreux compilateurs Cfloat , le type de données, par exemple, est représenté en 32 bits , conformément à la spécification IEEE pour les nombres à virgule flottante simple précision . Ils utiliseront donc des opérations de microprocesseur spécifiques à la virgule flottante sur ces valeurs (addition à virgule flottante, multiplication, etc.).
La plupart des types de données statistiques ont des types comparables en programmation informatique, et vice versa, comme le montre le tableau suivant :
Définition
Parnas, Shore et Weiss (1976) ont identifié cinq définitions d'un « type » qui ont été utilisées, parfois implicitement, dans la littérature :
- Syntactique
- Un type est une étiquette purement syntaxique associée à une variable lors de sa déclaration. Bien qu'utiles pour les systèmes de types avancés tels que les systèmes de types sous-structurels , de telles définitions ne fournissent aucune signification intuitive des types.
- Représentation
- Un type est défini en termes d’une composition de types plus primitifs, souvent des types de machines.
- Représentation et comportement
- Un type est défini comme sa représentation et un ensemble d' opérateurs manipulant ces représentations.
- Espace de valeur
- Un type est un ensemble de valeurs possibles que peut posséder une variable. De telles définitions permettent de parler d'unions ( disjointes ) ou de produits cartésiens de types.
- Espace de valeur et comportement
- Un type est un ensemble de valeurs qu'une variable peut posséder et un ensemble de fonctions que l'on peut appliquer à ces valeurs.
La définition en termes de représentation était souvent réalisée dans des langages impératifs tels qu'ALGOL et Pascal , tandis que la définition en termes d'espace de valeurs et de comportement était utilisée dans des langages de plus haut niveau tels que Simula et CLU . Les types incluant un comportement s'alignent plus étroitement sur les modèles orientés objet , alors qu'un modèle de programmation structuré aurait tendance à ne pas inclure de code et est appelé " structures de données simples" .
Classification
Les types de données peuvent être classés en fonction de plusieurs facteurs :
- Les types de données primitifs ou types de données intégrés sont des types intégrés à une implémentation de langage. Les types de données définis par l'utilisateur sont des types non primitifs. Par exemple, les types numériques de Java sont primitifs, tandis que les classes sont définies par l'utilisateur.
- Une valeur de type atomique est un élément de données unique qui ne peut pas être divisé en parties composantes. Une valeur de type composite ou de type agrégé est une collection d'éléments de données accessibles individuellement. Par exemple, un entier est généralement considéré comme atomique, bien qu'il soit constitué d'une séquence de bits, tandis qu'un tableau d'entiers est certainement composite.
- Les types de données de base ou types de données fondamentaux sont définis axiomatiquement à partir de notions fondamentales ou par l'énumération de leurs éléments. Les types de données générés ou types de données dérivés sont spécifiés, et partiellement définis, en termes d'autres types de données. Tous les types de base sont atomiques. Par exemple, les entiers sont un type de base défini en mathématiques, tandis qu'un tableau d'entiers est le résultat de l'application d'un générateur de type de tableau au type entier.
La terminologie varie : dans la littérature, les termes primitif, intégré, basique, atomique et fondamental peuvent être utilisés de manière interchangeable.
Exemples
Types de données de la machine
Toutes les données des ordinateurs basés sur l'électronique numérique sont représentées sous forme de bits (alternatives 0 et 1) au niveau le plus bas. La plus petite unité de données adressable est généralement un groupe de bits appelé octet (généralement un octet , qui fait 8 bits). L'unité traitée par les instructions du code machine est appelée mot (en 2011 , généralement 32 ou 64 bits).
Les types de données machine exposent ou rendent disponible un contrôle précis du matériel, mais cela peut également exposer des détails d'implémentation qui rendent le code moins portable. Par conséquent, les types de machines sont principalement utilisés dans la programmation système ou les langages de programmation de bas niveau . Dans les langages de niveau supérieur, la plupart des types de données sont abstraits dans le sens où ils n'ont pas de représentation machine définie par le langage. Le langage de programmation C , par exemple, fournit des types tels que les booléens, les entiers, les nombres à virgule flottante, etc., mais les représentations binaires précises de ces types sont définies par l'implémentation. Le seul type C avec une représentation machine précise est le chartype qui représente un octet.
Type booléen
Le type booléen représente les valeurs true et false . Bien que seules deux valeurs soient possibles, elles sont plus souvent représentées sous forme de mot plutôt que sous forme de bit unique, car il faut plus d'instructions machine pour stocker et récupérer un bit individuel. De nombreux langages de programmation n'ont pas de type booléen explicite, mais utilisent plutôt un type entier et interprètent (par exemple) 0 comme false et les autres valeurs comme true. Les données booléennes font référence à la structure logique de la façon dont le langage est interprété par le langage machine. Dans ce cas, un booléen 0 fait référence à la logique False. True est toujours une valeur différente de zéro, en particulier une valeur un qui est connue sous le nom de booléen 1.
Types numériques
Presque tous les langages de programmation fournissent un ou plusieurs types de données entiers . Ils peuvent soit fournir un petit nombre de sous-types prédéfinis limités à certaines plages (comme shortet longet leurs unsignedvariantes correspondantes en C/C++) ; soit permettre aux utilisateurs de définir librement des sous-plages telles que 1..12 (par exemple Pascal / Ada ). Si un type natif correspondant n'existe pas sur la plate-forme cible, le compilateur les décomposera en code à l'aide de types qui existent. Par exemple, si un entier 32 bits est demandé sur une plate-forme 16 bits, le compilateur le traitera tacitement comme un tableau de deux entiers 16 bits.
Les types de données à virgule flottante représentent certaines valeurs fractionnaires ( des nombres rationnels , mathématiquement parlant). Bien qu'ils aient des limites prédéfinies à la fois sur leurs valeurs maximales et leur précision, ils sont parfois appelés à tort réels (évoquant les nombres réels mathématiques ). Ils sont généralement stockés en interne sous la forme a × 2 b (où a et b sont des entiers), mais affichés sous la forme décimale familière .
Les types de données à virgule fixe sont pratiques pour représenter des valeurs monétaires. Ils sont souvent implémentés en interne sous forme d'entiers, ce qui conduit à des limites prédéfinies.
Pour une indépendance par rapport aux détails de l'architecture, un type Bignum ou de précision arbitraire
numeric peut être fourni. Cela représente un entier ou un rationnel avec une précision limitée uniquement par la mémoire disponible et les ressources de calcul sur le système. Les implémentations Bignum d'opérations arithmétiques sur des valeurs de la taille d'une machine sont nettement plus lentes que les opérations machine correspondantes.
Énumérations
Le type énuméré possède des valeurs distinctes, qui peuvent être comparées et assignées, mais qui n'ont pas nécessairement de représentation concrète particulière dans la mémoire de l'ordinateur ; les compilateurs et les interprètes peuvent les représenter de manière arbitraire. Par exemple, les quatre couleurs d'un jeu de cartes peuvent être quatre énumérateurs nommés CLUB , DIAMOND , HEART , SPADE , appartenant à un type énuméré nommé suit . Si une variable V est déclarée comme ayant suit comme type de données, on peut lui assigner n'importe laquelle de ces quatre valeurs. Certaines implémentations permettent aux programmeurs d'assigner des valeurs entières aux valeurs d'énumération, ou même de les traiter comme des équivalents de type à des entiers.
Types de chaîne et de texte
Les chaînes sont une séquence de caractères utilisée pour stocker des mots ou du texte brut , le plus souvent des langages de balisage textuel représentant du texte formaté . Les caractères peuvent être une lettre d'un alphabet , un chiffre, un espace vide, un signe de ponctuation, etc. Les caractères sont tirés d'un jeu de caractères tel que l'ASCII . Les types de caractères et de chaînes peuvent avoir différents sous-types selon le codage des caractères. L'ASCII original de 7 bits de large s'est avéré limité et a été remplacé par des jeux de 8, 16 et 32 bits, qui peuvent coder une grande variété d'alphabets non latins (tels que l'hébreu et le chinois ) et d'autres symboles. Les chaînes peuvent être de longueur variable ou fixe, et certains langages de programmation ont les deux types. Elles peuvent également être sous-typées en fonction de leur taille maximale.
La plupart des jeux de caractères incluant les chiffres , il est possible d'avoir une chaîne numérique, telle que "1234". Ces chaînes numériques sont généralement considérées comme distinctes des valeurs numériques telles que 1234, bien que certaines langues effectuent automatiquement la conversion entre elles.
Types de syndicats
Une définition de type d'union spécifiera lequel des nombreux sous-types autorisés peut être stocké dans ses instances, par exemple « float ou long entier ». Contrairement à un enregistrement , qui pourrait être défini pour contenir un float et un entier, une union ne peut contenir qu'un seul sous-type à la fois.
Une union marquée (également appelée variante , enregistrement de variante, union discriminée ou union disjointe) contient un champ supplémentaire indiquant son type actuel pour une sécurité de type améliorée.
Types de données algébriques
Un type de données algébrique (ADT) est un type de somme éventuellement récursif de types de produits . Une valeur d'un ADT se compose d'une balise de constructeur ainsi que de zéro ou plusieurs valeurs de champ, le nombre et le type des valeurs de champ étant fixés par le constructeur. L'ensemble de toutes les valeurs possibles d'un ADT est l'union disjointe (somme) selon la théorie des ensembles des ensembles de toutes les valeurs possibles de ses variantes (produit de champs). Les valeurs des types algébriques sont analysées à l'aide d'une correspondance de motifs, qui identifie le constructeur d'une valeur et extrait les champs qu'il contient.
S'il n'y a qu'un seul constructeur, l'ADT correspond alors à un type de produit similaire à un tuple ou à un enregistrement. Un constructeur sans champ correspond au produit vide (type d'unité). Si tous les constructeurs n'ont pas de champ, l'ADT correspond alors à un type énuméré .
Un ADT courant est le type d'option , défini dans Haskell comme . dataMaybea=Nothing|Justa
Structures de données
Certains types sont très utiles pour stocker et récupérer des données et sont appelés structures de données . Les structures de données courantes incluent :
- Un tableau (également appelé vecteur, liste ou séquence) stocke un certain nombre d'éléments et fournit un accès aléatoire à des éléments individuels. Les éléments d'un tableau doivent généralement (mais pas dans tous les contextes) être du même type. Les tableaux peuvent être de longueur fixe ou extensibles. Les indices d'un tableau doivent généralement être des entiers (sinon, on peut souligner cette relaxation en parlant d'un tableau associatif ) d'une plage spécifique (si tous les indices de cette plage ne correspondent pas à des éléments, il peut s'agir d'un tableau clairsemé ).
- Les enregistrements (également appelés tuple ou structure) font partie des structures de données les plus simples . Un enregistrement est une valeur qui contient d'autres valeurs, généralement en nombre et en séquence fixes et généralement indexées par des noms. Les éléments des enregistrements sont généralement appelés champs ou membres .
- Un objet contient un certain nombre de champs de données, comme un enregistrement, et propose également un certain nombre de sous-routines pour y accéder ou les modifier, appelées méthodes .
- la liste chaînée simple , qui peut être utilisée pour implémenter une file d'attente et est définie dans Haskell comme ADT , et
dataLista=Nil|Consa(Lista) - l' arbre binaire , qui permet une recherche rapide, et peut être défini en Haskell comme l'ADT
dataBTreea=Nil|Node(BTreea)a(BTreea)
Types de données abstraits
Un type de données abstrait est un type de données qui ne spécifie pas la représentation concrète des données. À la place, une spécification formelle basée sur les opérations du type de données est utilisée pour le décrire. Toute implémentation d'une spécification doit respecter les règles données. Par exemple, une pile comporte des opérations push/pop qui suivent une règle Last-In-First-Out et peuvent être concrètement implémentées à l'aide d'une liste ou d'un tableau. Les types de données abstraits sont utilisés dans la sémantique formelle et la vérification de programmes et, de manière moins stricte, dans la conception .
Pointeurs et références
Le principal type dérivé non composite est le pointeur , un type de données dont la valeur fait directement référence à (ou « pointe vers ») une autre valeur stockée ailleurs dans la mémoire de l'ordinateur à l'aide de son adresse . Il s'agit d'un type de référence primitif . (En termes courants, un numéro de page dans un livre pourrait être considéré comme une donnée qui fait référence à une autre). Les pointeurs sont souvent stockés dans un format similaire à un entier ; cependant, tenter de déréférencer ou de « rechercher » un pointeur dont la valeur n'a jamais été une adresse mémoire valide provoquerait le blocage d'un programme. Pour améliorer ce problème potentiel, un type de pointeur est généralement considéré comme distinct du type entier correspondant, même si la représentation sous-jacente est la même.
Types de fonctions
Les langages de programmation fonctionnelle traitent les fonctions comme un type de données distinct et permettent aux valeurs de ce type d'être stockées dans des variables et transmises à des fonctions. Certains langages multi-paradigmes tels que JavaScript disposent également de mécanismes permettant de traiter les fonctions comme des données. des systèmes de types contemporains vont au-delà du simple type « objet fonction » de JavaScript et disposent d'une famille de types de fonctions différenciées par des types d'arguments et de retour, tels que le type Int -> Booldésignant les fonctions prenant un entier et renvoyant un booléen. En C, une fonction n'est pas un type de données de première classe, mais les pointeurs de fonction peuvent être manipulés par le programme. Java et C++ n'avaient à l'origine pas de valeurs de fonction, mais les ont ajoutées dans C++11 et Java 8.
Constructeurs de types
Un constructeur de type crée de nouveaux types à partir d'anciens types et peut être considéré comme un opérateur prenant zéro ou plusieurs types comme arguments et produisant un type. Les types de produits, les types de fonctions, les types de puissance et les types de listes peuvent être transformés en constructeurs de types.
Types quantifiés
Les types quantifiés universellement et existentiellement sont basés sur la logique des prédicats . La quantification universelle s'écrit ou et est l'intersection de tous les types du corps , c'est-à-dire que la valeur est de type pour chaque . La quantification existentielle s'écrit ou et est l'union de tous les types du corps , c'est-à-dire que la valeur est de type pour certains .
En Haskell, la quantification universelle est couramment utilisée, mais les types existentiels doivent être codés en se transformant exists a. f aen forall r. (forall a. f a -> r) -> rou un type similaire.
Types de raffinement
Un type de raffinement est un type doté d'un prédicat qui est supposé valable pour tout élément du type raffiné. Par exemple, le type des nombres naturels supérieurs à 5 peut s'écrire comme5\}}" data-src="https://wikimedia.org/api/rest_v1/media/math/render/svg/05fcfbcbdefc1ad08aedb78ecc7cc1d8b7db1efc">
Types dépendants
Un type dépendant est un type dont la définition dépend d'une valeur. Les fonctions dépendantes et les paires dépendantes sont deux exemples courants de types dépendants. Le type de retour d'une fonction dépendante peut dépendre de la valeur (et pas seulement du type) de l'un de ses arguments. Une paire dépendante peut avoir une deuxième valeur dont le type dépend de la première valeur.
Types d'intersections
Un type d'intersection est un type contenant les valeurs qui sont membres de deux types spécifiés. Par exemple, en Java, la classe Booleanimplémente à la fois les interfaces Serializableet Comparable. Par conséquent, un objet de type Booleanest un membre du type Serializable & Comparable. En considérant les types comme des ensembles de valeurs, le type d'intersection est l' intersection théorique des ensembles de et . Il est également possible de définir un type d'intersection dépendant, noté , où le type peut dépendre de la variable de terme .
Méta-types
Certains langages de programmation représentent les informations de type sous forme de données, ce qui permet l'introspection et la réflexion sur le type . En revanche, les systèmes de types d'ordre supérieur , tout en permettant la construction de types à partir d'autres types et leur transmission aux fonctions sous forme de valeurs, évitent généralement de baser les décisions informatiques sur eux.
Types de commodité
Pour plus de commodité, les langages de haut niveau et les bases de données peuvent fournir des types de données « du monde réel » prêts à l'emploi, par exemple des heures, des dates et des valeurs monétaires (devises). Ceux-ci peuvent être intégrés au langage ou implémentés en tant que types composites dans une bibliothèque.