Sûreté
Le langage Caml est sûr. Le compilateur effectue une vérification complète des programmes avant de permettre leur exécution. Ceci interdit de nombreuses erreurs de programmation, telles que, par exemple, confusion entre un entier et un pointeur, ou accès à un champ inexistant d'un enregistrement. Plus précisément, cela garantit l'intégrité des données manipulées par un programme Caml.
Bien qu'étant statiquement typé, Caml n'exige pas que les types des paramètres de fonctions, des variables locales, etc. soient explicitement déclarés, contrairement à, par exemple, C ou Java. Une grande partie de l'information de typage requise est automatiquement inférée par le compilateur.
Fonctions
Caml est un langage de programmation fonctionnel : il n'y a pas de restriction à la définition et à l'usage des fonctions. En d'autres termes, les fonctions sont des valeurs ordinaires: une fonction peut être passée en argument à une fonction ou renvoyée en tant que résultat par une fonction.
Traits impératifs
Caml offre la panoplie complète des traits de la programmation impérative. En particulier, variables, tableaux, et composantes des enregistrements peuvent être déclarés modifiables. Plusieurs formes de boucles sont disponibles.
Traitement des erreurs
Caml possède un mécanisme général d'exceptions, pour signaler et traiter les erreurs et les situations exceptionnelles.
Types de données
Il existe en Caml de nombreux types de données prédéfinis, parmi lesquels :
- types de base : entiers, flottants, booléens, caractères, chaînes de caractères.
- types de données plus complexes : n-uplets, tableaux, listes, ensembles, tables de hachage, files, piles, flux de données.
Au-delà de ces types prédéfinis, Caml propose de puissants moyens de définir de nouveaux types : types enregistrements, types énumérés, et types sommes généraux. Les types sommes sont une généralisation simple et puissante des types énumérés. Ils permettent de regrouper des valeurs hétérogènes au sein d'un même type, grâce à l'emploi d'étiquettes appelées constructeurs de données.
Les types définis dans un module peuvent être rendus visibles aux clients de ce module de façon soit concrète soit abstraite, au gré du programmeur. Lorsqu'un type est exporté sous forme concrète, sa définition complète reste connue, et les clients du module peuvent donc construire ou examiner des valeurs de ce type. Au contraire, lorsqu'un type est exporté sous forme abstraite, seul son nom est connu à l'extérieur du module. Il devient alors impossible, depuis l'extérieur, de créer ou d'inspecter des valeurs de ce type.
Ce mécanisme autorise un contrôle fin du degré d'encapsulation des données manipulées par les programmes, ce qui est indispensable pour la programmation à grande échelle.
Aptitude au calcul symbolique
Caml permet le filtrage, une généralisation de l'analyse par cas traditionnelle. Le filtrage fournit un moyen concis et élégant d'analyser et de nommer les données simultanément. Le compilateur Caml tire avantage de ce trait pour soumettre le code à plusieurs vérifications : branches superflues et branches manquantes sont détectées et signalées, ce qui permet souvent d'éliminer de subtiles erreurs. Lorsqu'aucune erreur n'est signalée, on peut avoir la certitude qu'aucun cas n'a été oublié.
Le filtrage apporte un confort et un niveau de sécurité inégalés dans le traitement des données de nature symbolique.
Polymorphisme
Caml est doté d'un système de types polymorphe : certains types indéterminés peuvent être représentés par des variables, qui seront ensuite instanciées à volonté. Ainsi, par exemple, une même fonction de tri peut être employée pour trier des listes d'entiers, des listes de paires d'entiers, ou des listes d'enregistrements, sans qu'aucune duplication de code ne soit nécessaire.
Programmation à grande échelle
Un programme Caml est formé d'unités de compilation que le compilateur traite séparément. Cette organisation est entièrement compatible avec l'utilisation d'outils traditionnels de gestion de projets, comme l'utilitaire « make ». Le système de modules de Caml est puissant et sûr: toutes les interactions entre modules sont vérifiées statiquement lors du contrôle des types. Dans le cas d'OCaml, un module peut comporter des sous-modules, ce qui permet une organisation hiérarchique, et il est possible de paramétrer un module par d'autres modules, ou, en d'autres termes, de définir des fonctions des modules dans les modules.
Programmation orientée objets
OCaml permet l'écriture de programmes en style orienté objets. Fidèle à la philosophie du langage, la couche orientée objets obéit au paradigme du « typage fort » : ainsi, il est impossible d'envoyer à un objet un message auquel il serait incapable de répondre. Cette sûreté ne compromet en rien l'expressivité du langage: grâce, entre autres, à des traits tels que l'héritage multiple et les classes paramétrées, les « design patterns » les plus complexes s'expriment de façon naturelle.
Gestion mémoire automatisée et incrémentale
Caml offre une gestion automatique de la mémoire : l'allocation et la libération des structures de données est implicite et laissée à la charge du compilateur: il n'y a pas d'opérateur « new », « malloc », « delete » ou « free ». Cela rend les programmes beaucoup plus sûrs: toute corruption de la mémoire est impossible.
De plus, le gestionnaire de mémoire est incrémental: il s'intercale dans l'exécution de l'application, de sorte que la récupération mémoire ne provoque pas de délais notables.
Méthode d'évaluation
La stratégie d'évaluation de Caml est stricte. Lorsqu'un mode d'évaluation paresseux est nécessaire, celui-ci peut être simulé à l'aide de suspensions explicites. Ainsi, il est possible, par exemple, de manipuler des flux de données potentiellement infinis.
Compilateur rapide, code exécutable rapide
OCaml propose deux compilateurs en ligne de commande: un compilateur vers code-octets et un compilateur vers code natif. Tous deux permettent la compilation séparée. Caml Light ne propose qu'un compilateur vers code-octets.
Les compilateur vers code-octets produisent des exécutables légers et portables. De plus, ces compilateurs sont extrêmement rapides.
Le compilateur vers code natif produit un code machine plus efficace, dont la vitesse d'exécution est digne des meilleurs compilateurs disponibles actuellement.
Interactivité
Caml offre également un système interactif (une boucle de lecture-évaluation-impression des résultats), qui est pratique pour apprendre le langage ou bien pour tester puis corriger ses programmes : on n'est pas obligé de créer un fichier, ni d'insérer des ordres d'impression dans les programmes puisque les résultats sont imprimés automatiquement par le système interactif.
Mise au point des programmes
Il existe plusieurs méthodes de mise au point des programmes Caml :
- Le système interactif offre une méthode élémentaire mais très simple et rapide pour tester de (petites) fonctions : on vérifie simplement les résultats obtenus pour quelques exemples tapés directement dans la boucle d'interaction.
- dans les cas plus complexes, le système interactif permet également de suivre à peu de frais la progression des calculs, grâce au mécanisme de trace des appels de fonctions.
- enfin, le débogueur symbolique avec retour en arrière permet de suivre très finement le déroulement de l'exécution, de l'arrêter à tout moment pour examiner l'état courant des variables et de la pile des fonctions appelantes, et même de revenir en arrière dans les calculs pour reprendre l'exécution au moment où un événement intéressant se produit.
Analyse syntaxique
Caml offre des outils de génération d'analyseurs syntaxiques analogues à « lex » et « yacc ». De plus, il propose un type de flux de données prédéfini, ce qui permet de définir aisément des analyseurs récursifs descendants LL(1).