Futur Mac

Comparaison des langages de programmation

[en cours de rédaction]

La machine à tout faire qu'est l'ordinateur, ne sait rien malheureusement rien faire toute seule… il faut tout lui expliquer. Malheureusement, cette dernière, pas très intelligente ne comprend que des textes écrits dans une langue très stricte, surtout pour ce qui est de la ponctuation. Ces langues, sont couramment appelées «langages de programmation».

Ces langages sont très nombreux (plus d'un millier !), il faut donc en choisir un pour programmer (expliquer à la machine comment faire pour reprendre la métaphore précédente). Ce choix est d'autant plus difficile que ces langages semblent tous se ressembler plus ou moins. J'espère via cet article de vous faire comprendre quels sont les points importants à comparer avant de faire son choix.

Ici je resterais assez général afin d'apporter une vision d'ensemble, mais d'autres articles suivront, avec des descriptions plus précises de différents langages.

Qu'est-ce qu'un programme

Je ne rentrerais pas ici dans les détails de la théorie des programmes informatique, je resterais dans une description naïve mais toutefois assez utile pour comprendre les différences profondes entre les différents langages.

Différentes conceptions de langages

Un programme est tout d'abord une suite d'ordres, d'instructions. Chaque ordre est constitué d'un «verbe» désignant l'opération à effectuer, et des arguments spécifiant comment effectuer cette action, sur qui avec quoi… Les «qui», «quoi», «comment» sont les données que le programme manipule.

On voit déjà qu'il y a deux grands types de conception de langage qui apparaissent :

La différence peut sembler minime, mais elle est en fait immense : dans le cas des langages objects, il est possible de définir des méthodes de même nom pour plusieurs objects différents et donc de pouvoir demander l'exécution d'une méthode sans savoir exactement quel type d'objet on manipule. On pourrait imaginer un système similaire avec les langages classiques où dans une fonction on testerait d'abord le type des objets passés puis ensuite exécuterait l'action correspondant au type trouvé. Malheureusement il est alors impossible de séparer logiquement le code associé à un type d'objet de celui associé à un autre type : les deux codes sont mixés dans toutes les fonctions. Avec les languages objets, celà n'est plus vrai puisque tout le code est organisé par objet, et non par opération. [TODO : devient trop long/complexe]

Il existe une autre grande catégorie de langages, les langages fonctionnels comme Lisp, Scheme, OCaml. Ceux-ci, contrairement aux deux autres qui marquent une forte séparation entre les objets et les opérations, considère qu'une fonction est un objet comme un autre. On peut donc les manipuler, les passer en paramêtres composer/concaténer/comparer avec une autre… et donc avoir un programme qui créer son propre code au fur et à mesure (on peut aussi comparer avec les opréteurs sur les fonctions en math qui servent à calculer sur les fonctions : composition, dérivation…). Pour le programmeur lambda, celà n'a pas grand intérêt. Cependant dans des domaines comme l'intelligence artificielle cela retrouve de son intérêt : un programme «intelligent» doit pouvoir apprendre et évoluer. Les langages fonctionnels sont souvent très pratique et performant pour écrire des algorithmes complexes (souvent récursifs d'ailleurs), mais sont moins approriés pour écrire des programmes très séquentiels.

Structure de contrôle : gestion des erreurs

Si un programme n'était qu'une suite d'instructions linéraire, il serait alors impossible de modifier le comportement de son programme selon son environnement. C'est la qu'apparaissent les structures de contrôle, en particulier le sacro-saint «if» qui d'ailleurs suffit à écrire les autres (seul le if est codé dans un processeur, pas de for, while…). Je ne m'attarderais pas sur les «while», «for», «switch» qu'on retrouve quasiment partout, tellement ceux-ci sont indispensables et bien connus. Par contre, il y en a un très intéressant et souvent très pratique dans la gestion des erreurs : les exceptions.

Dans un programme classique, lorsqu'une dans une fonction rencontre un problème pour effectuer son traitement, elle doit disposer d'un moyen d'informer la fonction appelante qu'elle a du abandonner le traitement. Il y a plusieurs méthode pour arrivé à cela :

Pour comparer les exceptions avec la gestion classique des erreur, voilà un petit exemple (avec des fonctions susceptible de gérer le même genre d'erreur, ce qui est le cas quand on lit le contenu d'un fichier, ou une connexion réseau : il est à tout moment possible d'obtenir une erreur "fin de fichier atteint" ou "connexion fermée")  :

essayer de faire : (l'exécution s'arrète à la première fonction qui génère une erreur)
    fonction1
    fonction2
    fonction3
si une erreur truc s'est produite faire :
    ...
si en fait c'était une erreur machin faire :
    ...
fin

Dans le cas classique on aurait eu :

fonction1
si une erreur truc s'est produite faire : ...
si en fait c'était une erreur machin faire : ...
si c'était une autre erreur : ...
fonction2
si une erreur truc s'est produite faire : ...
si en fait c'était une erreur machin faire : ...
si c'était une autre erreur : ...
fonction3
si une erreur truc s'est produite faire : ...
si en fait c'était une erreur machin faire : ...
si c'était une autre erreur : ...

Par ailleurs, dans le cas classique, il est important de traiter toutes les erreurs (sinon les résultats des fonctions suivantes peuvent être complètement aberrants). Avec les exceptions, vu que l'exécution est stoppée à la première erreur, cela n'arrive jamais même si une erreur n'est pas traité puisque la fonction regénérera automatiquement la même erreur qui remontera ainsi les appels de fonctions.

Organisation du code des programmes, principe des bibliothèques

Histoire d'éviter de recopier du code, ce qui devient vite ingérable en maintenabilité, nos prédécesseurs ont inventés la notion de fonction. Ça paraît une évidence aujourd'hui, mais il y à peine dix ans, ce n'était pas toujours le cas (rappelez vous des divers basics, sans aucune gestion de fonctions). Cela revient en fait à créer ses propres opérations et donc étendre les opérations élémentaires du processeur.

Il y existe des banques fonctions disponibles, regroupés dans ce qu'on appelle une bibliothèque («library» en anglais). Derrière cela, il y a un problème non évident à résoudre : avoir une compatibilité entre une bibliothèque créer avec un compilateur/langage donnée et une autre bibliothèque créer avec un autre. C'est quelque chose qui est bien normalisé sur un couple système/processeur donnée pour ce qui est des appels de fonctions classique et la définition des structures de données en mémoire. Mais ce n'est malheureusement pas le cas

API standards

TODO

Système RPC (Remote procédure call)

TODO