blog2geek.com
LLBAvatar de LLB

38 billets | Profil

Recherche Google

ce blog tous
Derniers billets Connexion
Archives

test

06/11/2006

[Lang] [Caml] De l'importance du typage.

De l'importance du typge.

Caml est un langage fortement et statiquement typé, avec une inférence de types.

Un langage est statiquement typé si le type de la donnée est associé au nom de la variable, plutôt qu'à sa valeur. Le type de la variable est donc connu dès la déclaration et ne peut plus changer. À chaque affectation une vérification est donc faite : il faut que la valeur reçue soit compatible avec le type de la variable. De plus, chaque fonction doit connaitre le type de ses arguments, et une vérification est faite à chaque appel de fonction.

Quel intérêt ? Tout d'abord, ça permet de vérifier le code dès la compilation. Cela rend le programme beaucoup plus sûr : les erreurs de types sont détectées au plus tôt, et on n'a pas besoin de tester entièrement chaque branche du code pour s'assurer qu'il est correct.

Les langages compilés ont souvent un typage statique. Cela permet surtout de simplifier le code du compilateur et d'optimiser le code produit : on connait la taille de chaque variable à la compilation.

 

Un langage est fortement typé quand le système de types est complet, qu'il n'autorise pas les conversions implicites entre différents types. Par exemple, un langage fortement typé fera la différence entre un entier, un caractère, une énumération et un booléen (contrairement au C).

L'inférence de types est un système très complexe permettant de déduire à la compilation le type d'une variable, d'un argument, d'une fonction... Premier avantage : cela fait moins de code à taper. Deuxième avantage : le code est plus lisible (les annotations de types servant surtout au compilateur). Troisième avantage : on peut manipuler des types très complexes de manière tout à fait naturelle e transparente (manipuler des types faisant plus de 5 lignes est rédibitoire lorsque l'on doit les taper à chaque fois). Je reviendrai sur ce dernier point lorsque je parlerai du typage structurel et du duck typing.

 

Le C est faiblement typé. Il permet de faire ce genre de commandes particulièrement dangereuses :

char c = 400;
int a = 'L'
typedef enum color { white, red } e_color;
e_color e = 4;

int i = strlen(0);

Il est probable qu'une personne écrivant ce genre de lignes fasse une erreur. Et pourtant, le compilateur ne dit rien (enfin, juste un warning pour la première instruction). En C, tu fais une erreur, et le compilateur ne te le dira pas. Avec un peu de chance, tu auras un segfault à l'exécution. Au pire, l'erreur se propagera dans le reste du code. Dans de telles conditions, le débuggage peut être particulièrement long et pénible. C'est entre autres pour cela que je déteste ce langage.

 

Beaucoup de langages de script sont dynamiquement typés. Cela signifie qu'il n'est pas possible de vérifier le typage d'un programme autre qu'en l'exécutant... et encore ! Exécuter avec succès le programme ne garantit pas qu'il est valide. Il faudrait pouvoir entrer dans toutes les branches du programme. D'une manière générale, on ne peut pas être sûr que ce qu'on a écrit fonctionne correctement. Il faut beaucoup tester avant de pouvoir faire confiance à son programme.

Une erreur de programmation fréquente est d'oublier d'initialiser une variable. En C, la valeur de la variable est alors quelconque. Quoi de plus dangereux ?

En Ruby, une variable non définie vaut "nil". Ça ne vaut pas beaucoup mieux. L'erreur a alors une très forte probabilité de se propager dans le code. Le message d'erreur (à l'exécution) ne donnera donc pas la bonne ligne. Quel dommage !

En Java, un Integer peut valoir null. Une fonction qui attend un Integer en argument peut donc recevoir null ? On retrouve donc le même problème qu'en Ruby, alors que Java est censé être typé statiquement.

Integer a = null;
println(a.intValue());
Cela provoque une erreur à l'exécution, non détectée à la compilation. 

En Caml, rien de tout cela n'arrive. Il est syntaxiquement impossible de déclarer une variable sans lui donner de valeur. Une fonction prenant un objet en argument refusera toute autre chose, y compris les valeurs nulles. Si l'on veut qu'une fonction prenne soit un entier, soit null (que l'on appelle souvent "None" en Caml), on est obligé d'en tenir compte dans le code de la fonction. Et on ne pourra pas accéder à l'entier s'il y a la moindre chance que ce soit null.

Si l'on veut par exemple définir la fonction next qui renvoie le suivant si on a un entier, et 0 si c'est null, on écrira par exemple :

let next = function
| Some x -> x + 1
| None -> 0

Quand on écrit cette fonction, on est sûr à 100% qu'elle ne pourra jamais provoquer d'erreur à l'exécution, simplement parce que le compilateur l'a vérifiée. Ce n'est absolument le cas quand on écrit ce genre de fonction en C, C++, Java, C#, Ruby, Python, etc.

Caml refuse de compiler lors de la moindre erreur de typage. Il indique l'erreur et explique au développeur pourquoi il écrit de la merde. Et cela augmente considérablement la productivité.

> Rédiger un commentaire

00:10 12/01/2007 - inconnu

Je trouve ta définition de "typage statique" assez bof. Le contraire de celle que tu donnes pour "typage dynamique" serait bien meilleure :le typage est statique quand on peut connaître tous les types sans exécuter le code.
Ah, et on n'écrit pas les mots "dynamiquement typé" dans ce sens là, mais à force de lire de la doc en anglais sur le sujet, ça devient naturel :/
-- 
Rubix 

> Rédiger un commentaire