Aller au contenu

Les types

🤖 Rédaction assistée par IA.

Définition

Un type définit l'ensemble des valeurs possibles d'une donnée et les opérations autorisées sur ces valeurs.

Quel que soit le langage de programmation utilisé, une valeur aura toujours un type. Il permettra par exemple d'avoir comme résultat :

  • 5 pour l'addition de deux nombres 2 et 3
  • "23" pour la concaténation de deux chaînes de caractères "2" et "3"

En pratique

Les types primitifs

Les langages fournissent des types primitifs (ou types de base) dont le nommage varie :

Type TypeScript Java Python C++ PHP
Entier number, bigint int, long... int int, long... int
Flottant number float, double float float, double float
Booléen boolean boolean bool bool bool
Caractère - char - char -
Chaîne de caractères string String1 str std::string1 string
Absence de valeur null, undefined, void null, void None nullptr, void null, void

Typage statique ou dynamique

En fonction du langage :

  • Avec un typage statique, le type des variables est connu et vérifié à la compilation. Il n'a pas forcément à être écrit grâce à l'inférence de type (ex : let x = 5; en Rust, var en Java, auto en C++).
  • Avec un typage dynamique, le type est porté par la valeur et vérifié à l'exécution (une même variable peut successivement contenir des valeurs de types différents).

Un nombre croissant de langages à typage dynamique permettent de déclarer des types (typage graduel) :

  • En PHP, les déclarations de type sont contrôlées à l'exécution.
  • En Python, les annotations de type (Python >= 3.5) ne sont pas contrôlées à l'exécution mais exploitées par des outils d'analyse statique (ex : mypy) et par les éditeurs.
  • TypeScript ajoute un typage statique à JavaScript : les types sont vérifiés à la compilation puis effacés dans le code JavaScript produit.

Voir Les spécificités des langages - Typage statique ou typage dynamique pour l'impact sur la conception.

Typage fort ou faible et conversions

Les notions de typage statique et dynamique ne doivent pas être confondues avec le typage fort et le typage faible qui caractérisent la tolérance du langage aux conversions implicites (ex : "2" + 3 vaut "23" en JavaScript, typage dynamique et faible, alors que Python lève une TypeError, typage dynamique et fort).

Dans tous les cas, il sera possible de procéder à des conversions explicites (cast) :

const n: number = Number("42"); // 42 (NaN si la conversion échoue)
const s: string = String(42);   // "42"
int n = Integer.parseInt("42"); // 42
String s = String.valueOf(42);  // "42"
int i = (int) 3.7;              // 3 (troncature)
n = int("42")  # 42
s = str(42)  # "42"
i = int(3.7)  # 3 (troncature)
int n = std::stoi("42");          // 42
std::string s = std::to_string(42); // "42"
int i = static_cast<int>(3.7);    // 3 (troncature)
$n = (int) "42";  // 42
$s = (string) 42; // "42"
$i = (int) 3.7;   // 3 (troncature)

Les tableaux

Un tableau regroupe des valeurs accessibles par leur indice (généralement à partir de 0, ex : t[0]). Nous distinguerons :

  • Les tableaux de taille fixe (ex : int t[3] en C++, new int[3] en Java)
  • Les tableaux de taille variable (ex : Array en JavaScript, list en Python, array en PHP, std::vector en C++, ArrayList en Java)

Voir Les structures de données pour les autres structures (listes, piles, files, dictionnaires...).

Les types définis par l'utilisateur

La plupart des langages permettent de définir de nouveaux types.

Les structures

Une structure regroupe plusieurs valeurs nommées (ses champs) au sein d'un même type. Par exemple, pour une coordonnée :

type Coordinate = {
    x: number;
    y: number;
};

const c: Coordinate = { x: 2.0, y: 3.0 };
from typing import TypedDict

Coordinate = TypedDict("Coordinate", {"x": float, "y": float})

c: Coordinate = {"x": 2.0, "y": 3.0}

Les champs sont vérifiés par les outils d'analyse statique (ex : mypy), pas à l'exécution.

struct Coordinate {
    double x;
    double y;
};

Coordinate c{2.0, 3.0};

Les énumérations

Une énumération définit un type dont les valeurs possibles sont listées explicitement :

enum Color {
    Red,
    Green,
    Blue,
}

const color: Color = Color.Green;
enum Color { RED, GREEN, BLUE }

Color color = Color.GREEN;
from enum import Enum


class Color(Enum):
    RED = 1
    GREEN = 2
    BLUE = 3


color = Color.GREEN
enum class Color { Red, Green, Blue };

Color color = Color::Green;
// PHP >= 8.1
enum Color
{
    case Red;
    case Green;
    case Blue;
}

$color = Color::Green;

Certains langages permettent d'associer des données à chaque valeur de l'énumération. C'est le cas de Rust :

enum Shape {
    Circle(f64),
    Rectangle(f64, f64),
}

fn area(shape: &Shape) -> f64 {
    match shape {
        Shape::Circle(r) => 3.14159 * r * r,
        Shape::Rectangle(w, h) => w * h,
    }
}

C'est ce mécanisme qui permet de construire les types Result et Option utilisés pour la gestion des erreurs.

Les alias de type

Un alias de type permet de nommer un type existant pour clarifier le code (ex : type Id = number en TypeScript, using Id = int; en C++, type Id = int en Python >= 3.12). Il n'existe pas d'équivalent en Java et en PHP.

Mises en garde

  • Les flottants sont des approximations : 0.1 + 0.2 ne vaut pas exactement 0.3 (voir 0.30000000000000004.com).
  • Les entiers ont une taille limitée dans la plupart des langages. En cas de dépassement, la valeur boucle en Java (Integer.MAX_VALUE + 1 vaut -2147483648), le comportement est indéfini pour les entiers signés en C++ et la valeur est convertie en float en PHP. Les entiers sont de taille arbitraire en Python (2**100 est calculé exactement).

Liens utiles


  1. En Java et en C++, les chaînes de caractères ne sont pas des types primitifs mais des classes (String en Java, std::string de la bibliothèque standard en C++). ↩↩