Ce type ne me revient pas !
Qu'est qu'un système de type ?
- Meta information attachée à une structure du langage
- Variable, fonction, expression ou module
Un type défini l'ensemble des valeurs possibles
//Attention code Groovy, parce que ca ressemble à Java en plus court !
//Type COLOR, 3 valeurs possibles
enum COLOR {
RED, BLUE, YELLOW
}
// Type Name, une infinité de valeur possibles
class Name {
String value
}
Un type défini quelles sont les opérations qui lui sont applicables
class Name {
String value
//Définition "interne"
Name lordify() {
return new Name(value:'sir ' + this.value)
}
}
class Lordificator {
//Définition "externe"
static Name lordify(Name name) {
return new Name(value:'sir ' + name.value)
}
}
Un type défini la façon dont est stockée la donnée
Float in32bit = 6.5f // sur 32 bits
Double in64bit = 6.5 // sur 64 bits
Un type défini le sens de la donnée
class Person {
//Plus de sens qu'une simple String
//Car on peut de cette façon limiter les opérations faisables
Name name
}
Pourquoi un système de type ?
- Définir des interfaces entres les "morceaux" d'un programme
- Ainsi diminuer les bugs en s'assurant que les morceaux sont connectés
de façon cohérente
- Lisibilité
- Optimisations
La vérification de type peut se faire
- Au moment de la compilation (vérification statique)
- Au moment de l'exécution (vérification dynamique)
Le typage statique
Un système de typage statique pour un langage Turing-Complet doit :
- être "sound" : rejeter les programmes invalides
- être décidable : il est possible d'écrire un algorithme déterminant
si le programme est bien typé
Limite du typage statique
- il est toujours possible d'écrire un programme "juste"
mais qui sera rejeté par le compilateur
(la preuve dérive du theorème d'incomplétude de Gödel)
- Certaines fonctionnalités ne peuvent pas être vérifiées (downcasting, par exemple)
Java n'a pas un compilateur très puissant
//Ne compile pas
public class Exemple {
static Integer getIntOrZero(Object obj) {
if (obj instanceof Integer) {
return obj;
} else {
return 0;
}
}
}
Quelques langages statiquement typés
- Java
- Scala
- Ceylon
- Kotlin
- C
- C++
- Haskell
Le typage dynamique
- La vérification de la validité du programme se fait à l'exécution
Apport du typage dynamique : le Dynamic Dispatch
class Human {}
class Troll extends Human {}
public class Main {
public static void speak(Human h) {
System.out.println("Raconte des choses passionantes");
}
public static void speak(Troll h) {
System.out.println("Emacs c'est nul comparé à vim");
}
public static void main(String[] args) {
Human h = new Troll();
speak(h);
// En Java : la phrase d'humain normal
// En groovy : la phrase de troll
}
}
Apport du typage dynamique :Late Binding
- Late Binding = objet sur lequel on appelle la méthode
- Dynamic dispatch = quelle méthode on appelle
- N'existe donc pas vraiment Java
function makeTheDuckQuack(duck) {
//Ici le type de duck est inconnu,
//On ne le connaitra qu'à l'execution
duck.quack();
}
Apport du typage dynamique :la réflexion
- Pour pouvoir faire de la réflexion il faut connaitre les types au runtime !
Mais en Java, on peut faire de la réflexion !
C'est un langage à typage statique, non ?
Aspect Hybride
- La grand majorité des langages modernes à typage statique ont aussi une partie dynamique
public Integer castToInt(Number num) {
return (Integer) num;
}
//Le code ci-dessus renvoie une ClassCastException
//si le type de num n'est pas Integer
//Le type de num est donc accessible et vérifié au runtime !
Quelques langages mettant en avant le typage dynamique
- Groovy
- Clojure
- JavaScript
Static vs Dynamic
- Détection au plus tôt des bugs de type...
- ... même si ces bugs n'arrivent que rarement
- Oui, mais tous les bugs peuvent être considérés comme des erreurs de type...
- ... du moment que l'on utilise un langage avec un système de type suffisament puissant
Static vs Dynamic
- Le typage statique permet au compilateur de faire des optimisations...
- ... certains langages dynamiques permettent donc des annotations pour aider le compilateur
- Le typage dynamique permet au compilateur d'être plus rapide et de recharger à chaud ce qui diminue le temps de cycle
Static vs Dynamic
- La déclaration de type sert de documentation dans le code...
- ... mais sans inférence de type, elle diminue la lisibilité
Static vs Dynamic
- Les langages dynamiques permettent la metaprogrammation...
- ... meme si certains langages statiques possèdent des API de réflexion
Enfonçons le clou
- Un langage à typage dynamique impose que ses structures aient un type !
- Il y a donc bien des types en JS et PHP
- ASM, Brainfuck ou Whitespace sont des langages sans types
Typage explicite vs implicite
//Java
String explicit = "je suis explicitement une string";
//Scala
val implicit = "je suis implicitement une string"
-- haskell
let add x y = x + y
:info add
-- renvoie add :: Num a => a -> a -> a
-- l'utilisation de + a permis de typer implicitement les paramètres de add
Interlude
le typage faible et le typage fort
Un langage aurait un typage plus faible qu'un autre si :
- Il permet les conversions implicites
- Il permet l'arithmétique sur les pointeurs
- Il ne compile pas statiquement
- Il compile statiquement mais permet les erreurs de type au runtime
Exemple de langage fortement typé : JavaScript
var aNumber = 3;
function add(a, b) {
return a + b;
}
Exemple de langage faiblement typé : Scala
def isNegative(x:Number):Boolean = x.asInstanceOf[Float] < 0.0
Fin de l'interlude
- Toujours préférer d'autres termes que fort & faible
- Sauf si l'objectif est d'envenimer un débat
Le typage structurel
- La compatibilité de type est donnée par la structure et non par une déclaration explicite
- Par opposition au système de type nominatif
Exemple en TypeScript
interface Point {
x:number
y:number
}
function printPoint(p:Point) {
console.log('('+p.x+','+p.y+')')
}
printPoint({x:1, y:2})
Quelques langages typés structurellement
- Haskell
- OCaml
- TypeScript
- Dart
- Scala*
Le Duck Typing
- Typage structurel appliqué aux langages dynamiques
- Si ca marche comme un canard, nage comme un canard et
caquette comme un canard, alors c'est un canard
Exemple en ES6
function makeTheDuckQuack(duck) {
duck.quack();
}
class Duck {
quack() {
console.log('coin coin');
}
}
class Unicorn { }
makeTheDuckQuack(new Duck()); //coin coin
var unicorn = new Unicorn();
unicorn.quack = function() { console.log('COIN COIN'); };
makeTheDuckQuack(unicorn); // COIN COIN
makeTheDuckQuack(new Unicorn()); // type error
Quelques langages incluant Duck Typing
- Clojure
- JavaScript
- Groovy
Le typage graduel
- Permet au développeur de typer au choix à la compilation ou à l'execution
- Souvent confondu avec le typage optionnel (qui permet de désactiver le type checking)
- Utilisation d'un type joker any
Pourquoi TypeScript est presque réellement graduellement typé
function display(y : string) {
document.body.innerHTML = y.charAt(0);
// error au runtime: charAt is undefined, pas de check du type au runtime
}
var x : any = 3;
display(x);
Le typage dépendant
Un "type dépendant" est un type dépendant d'une valeur définie
Exemples
- Un Type "Nombre Entier compris entre 0 et n"
- Un type List indiquant la taille de la liste
- Un type Matrix indiquant la hauteur et la largeur de la matrice
Exemples de languages implémentant les types dépendants
Exemples (en Idris)
Vect.index 2 [3,4,5] -- renvoit 5
Vect.index 3 [3,4,5] -- ne compile pas
-- [3, 4, 5] est de type Vect 3 Integer