dimanche 18 janvier 2009

Basic

Le langage Basic a été créé au milieu des années 60 pour permettre aux étudiants non-scientifiques de programmer un ordinateur. Autrement dit, un langage de programmation pour les non-programmeurs.

On peut dire que le langage a remplit sa mission, puisque (avec peut-être un petit coup de pouce de Bill)  il est devenu le langage d'apprentissage par excellence.

Le premier impératif de ce type de langage est d'être simple. Mais qu'est ce que la simplicité? La théorie a une définition interessante, car elle utilise justement la notion de programme pour quantifier la complexité d'une entité, d'un objet ou d'une donnée: c'est la taille minimale du programme qui produit la donnée ou une description de l'entité considérée. Seulement, on sait qu'un tout petit programme peut être long à s'executer et produire une donnée particulièrement complexe (on peut penser à un programme de décompression par exemple); ce qui amène à considérer le temps d'éxécution de ce programme, et à la distinction deux types de complexités: la complexité dite "aléatoire", qui est en quelque sorte liée à la quantité de données que porte l'objet, et la complexité logique, qui représente le degré d'élaboration de l'objet, c'est à dire en quelque sorte la quantité de travail qu'a nécessité sa construction.

La théorie parle d'un programme, donc d'un langage de programmation. Quel langage utilise-t-elle? C? Basic? Haskell? Celui de la machine de Turing? En fait, peu importe, il suffit d'utiliser toujours le même langage pour pouvoir faire des comparaisons. 

Puisque le source d'un programme est une donnée (textuelle), on peut appliquer cette définition aux programmes eux-mêmes. En particulier, on peut utiliser cette métrique pour un même programme écrit dans différents langages. On devrait mesurer ainsi la complexité relative de différents langages. Toutefois, cela revient plu ou moins à compter les lignes de code, autrement dit au fameux indice "SLOC" (Source Lines Of Code), dont on sait qu'il doit être utilisé avec prudence.

Compter les lignes que l'on doit écrire dans un langage pour obtenir un résultat simple comme afficher "Bonjour tout le monde" est quand même révélateur de certaines choses intéressantes. Cela sépare grosso modo les langages en deux catégories:

* les langages qui le font en une  ligne,

* les langages qui le font en plus de lignes.

La théorie et l'expérience concordent: les programmes de la seconde catégorie, qui consistent généralement en l'instruction "afficher 'bonjour'" entourée de lignes de code dont l'utilité est plus ou moins claire pour un non-initié, sont subjectivement et objectivement plus complexes.

Une autre façon de comparer les langages plus qualitative que quantitative est de dénombrer le nombre de concepts utilisés de manière plus ou moins directe dans ces programmes. Basic par exemple, n'en utilise que deux: le concept d'instruction, et le concept de chaine de caractère. Un langage à objets un tant soit peu rigoureux utilise en plus la notion de classe (ou de méthode). Un langage purement fonctionnel utilisera une monade ou imposera de définir une fonction.

Du point de vue du non-programmeur ou du débutant, un langage appartenant à la première catégorie comme Basic semble préférable, parce qu'il permet d'atteindre un objectif de manière simple. Pourquoi s'encombrer de lignes ou de concepts sans rapport direct avec le problème à résoudre? Pourquoi le langage se jette-t-il en travers du chemin?

Il est évident que les langages sont rarement conçu pour être gratuitement complexes. Les complications qu'ils introduisent ont pour but de se conformer à un paradigme, qu'on estime profitable à moyen ou long terme de suivre. Les concepts imposés qui peuvent paraître a priori superflus sont en général des investissements visant à améliorer certaines qualités internes du programme, telles que la fiabilité ou la maintenabilité sur le long terme. 

Mais surtout, ces "complications" permettent d'aller plus loin avec le langage. La théorie dit que tous les langages qui sont capables de simuler une machine de Turing sont tous capables de faire la même chose. Et donc, le langage de la machine de Turing est aussi capable de réaliser les mêmes choses qu'un langage évolué comme Haskell, Lisp ou SmallTalk. On réalise immédiatement ce que cela vaut en pratique: il serait extrêmement difficile par exemple, de trier un tableau de chaînes de caractères avec une machine de Turing. Le même inconvénient frappe plus ou moins les langages simples comme Basic: la réalisation des fonctionnalités devient de plus en plus difficile à mesure que ces fonctions deviennent évoluées. Les langages simples "décrochent", tandis que les langages plus complexes peuvent suivre l'évolution des besoins de l'utilisateur. La comparaison des exemples de programmes "Hello, world" avec ceux réalisés pour un programme un peu plus élaboré comme "99 bouteilles de bière" esquisse un peu les limites de la simplicité à tout prix.

Ces qualités ne sont pas sans interêt pour le non-programmeur. Obtenir un programme qui marche dans les cas prévus est le premier objectif; mais il appréciera sans doute aussi que celui-ci ne plante pas lamentablement en cas d'erreur de saisie. Et il appréciera aussi de pouvoir le faire évoluer. Par définition, un non-programmeur n'a aucune idée de la façon d'obtenir ces qualités - voire à l'extrême, il n'en a pas toujours conscience a  priori. Enfin, le non-programmeur devient, par la force des choses, un peu programmeur et est logiquement amené à faire des programmes plus ambitieux à mesure que ces compétences s'améliorent. Un "guidage" du langage peut être un élément de satisfaction vis-à-vis du langage ("ce langage est super car il sûr et évolutif"), même s'il recent ce guidage comme une contrainte ou un obstacle.

Un exemple emblématique de cela est l'instruction GOTO de Basic, qui est incomparablement plus séduisante que la programmation structurée (voire "stricturée"), mais qui, pour le moins, à conduit plus d'un programme "fait à la maison" à l'effacement du fait qu'il n'était plus possible de le modifier sans engendrer une nuée de bogues. Dans le même registre mais de manière un peu plus subtile, certains estiment que les exceptions, un moyen relativement intuitif et séduisant pour résoudre le problème de la gestion d'erreur, sont des GOTO (à peine) déguisés.

Est-ce à dire que les langages "compliqués" seraient en réalité plus adaptés aux non-programmeurs? Il suffit de prendre un exemple extrême comme le langage Haskell, ou d'une autre manière, Forth, pour se convaincre du contraire. L'un est un langage d'universitaire, l'autre un langage de "vrai" programmeur. Ces langages semblent empreinter des voies très détournées pour atteindre l'objectif de faire un programme qui execute une tâche déterminée. Certes, ces langages "à forte personnalité" excellent à atteindre les objectifs secondaires pour lesquels ils sont construits (forte optimisation et simplicité de conception pour l'un, formalisme rigoureux pour l'autres), et ses objectifs secondaires sont sensés aider à atteindre le but principal et/ou maximiser une ou plusieurs des qualités évoquées plus haut.

Mais le revers de la médaille est que cette volonté d'excellence dans ces domaines secondaires obligent à sacrifier certaines aides directes à l'accomplissement du projet principal (syntaxe inhabituelle ou cryptographique, "surcharge" de concepts ou de connaissances prérequises), alors que l'utilisateur n'a pas forcément besoin d'une extrême fiabilité, optimisation ou évolutivité. Cette excellence est ce qu'on appelle de la "surqualité", une qualité ou niveau de qualité qui n'était pas requis initialement, et qui est en fait néfaste car elle entraîne toujours sous une forme ou une autre un coût qui n'est pas justifié (du point de vue du client ou de l'utilisateur final).

Un compromis entre une simplicité qui rend le langage accessible au premier abord et une complexité qui le rend utilisable sur le long terme est donc à trouver. La formule de ce subtil équilibre a déjà été en grande partie par le langage Lisp:

  1.  les clôtures ("closures"), des entités qui peuvent être difficiles à comprendre mais qui s'avèrent très utiles. Elles permettent notamment de construire un système orienté-objet si on le souhaite (voir CLOS).
  2. un système de "macros" qui tient la route (celui de C/C++ est à côté une mauvaise plaisanterie), et qui permet de rendre plus expressif le langage quand les choses se compliquent.   

Mais il a un défaut majeur: le manque de lisibité de sa syntaxe préfixe et sa célèbre surabondance de parenthèses. La lisibilité d'un langage est une qualité qu'on sous-estime ou sacrifie trop souvent. Un langage lisible permet de communiquer clairement le modus operandi d'un programme. On utilise souvent du "pseudo-code" à cette fin plutôt que d'utiliser le langage d'implémentation, et c'est à mon sens à porter au passif dudit langage. Un langage clair devient un langage de communication aussi avec les autres utilisateurs, plus approprié que la langue naturelle qui parfois trop floue ou ambigüe (pour ne pas paraphraser: "mieux vaut un petit programme qu'un long discours"), ce qui facilite l'apprentissage et permet la coopération.

mercredi 14 janvier 2009

Déclic?

Ce n'est pas la première fois qu'il me prend l'envie de créer un langage, au contraire; je suis sûr de retrouver en fouillant dans quelque vieux carton plusieurs ébauches de spécification de langage datant d'époques plus ou moins anciennes.

Pour tout dire, 4IM a été le seul qui a aboutit. Peut-être parce que je me suis contenté cette fois d'adapter un langage existant (Forth) à ma guise, plutôt que de partir d'une feuille blanche. Les autres ont rarement dépassé le stade de l'esquisse.

Cette envie me prend suite à des choses lues dans quelque livre ou magazine, encore lue sur interne, concernant les langages, les méthodes logicielles, ou les maths. L'idée de départ est donc purement technique.

Cette fois-ci, le déclic c'est produit alors que j'éditais une page Web relative à 4IM avec mon éditeur favori, et je trouvais particulièrement pénible d'avoir à enregistrer d'un côté, puis de passer au bureau suivant pour recharger la page dans le navigateur pour visualiser le résultat. La réflexion m'est venue que, avec toute l'artillerie logicielle dont ont dispose actuellement, il reste impossible d'obtenir aussi simple que celle-là. Il aurait suffit que mon éditeur favori envoie un simple signal à mon navigateur favori.

Il est possible que mon éditeur ou mon navigateur favori ne soient pas les meilleurs dans le domaine de la coopération entre applications, ou que je n'utilise pas les bons outils (pourquoi ne pas utiliser un éditeur spécialisé pour cela?), ou encore que la possibilité existe bien, et que je n'ai pas assez cherché. Même si la solution est bien dans l'une des ces propositions, sa mise en oeuvre demande des efforts ou a des inconvénients disproportionnés par rapport à l'idée simple et intuitive que peut avoir tout utilisateur lambda: que mon éditeur préféré envoie une commande de rechargement de sa page à mon éditeur préféré.

Le fameux adage "qui peut le plus, peut le moins" est si souvent pris à défaut qu'il faudrait à mon avis se décider un jour à adopter son contraire - ou est-ce une fausse impression due à ce que je suis très souvent aux prises avec des logiciels?

Evidemment, des monstres de puissance et de souplesse comme Firefox et Vi ne peuvent malgré tout pas résoudre chaque micro-problème de chaque utilisateur. Ce n'est pas un problème technique, car les auteurs de chacun des deux logiciels pourraient bricoler une solution en cinq minutes. C'est un problème similaire à celui de la "longue traine". En l'espèce, si ces logiciels satisfont les besoins courant d'un grand nombre d'utilisateurs dans un certain domaine, il existe au moins un aussi grand nombre d'utilisateurs avec des besoins particuliers qui ne sont pas satisfaits. En réalité, nous sommes tous un peu dans les deux catégories; c'est ce qui fait que les listes des doléances des logiciels ("les wishlists") ne se vident jamais et que pour la plupart des logiciels, les numéros de version ne cessent de s'incrémenter.

Cette situation était sans doute une fatalité il y a une vingt/trentaine d'années, quand ni l'internet ni le logiciel libre n'existaient, et que les ordinateurs étaient de bien étranges boîtes dont on ne savait pas encore bien quoi faire. Je pense que ce modèle issue de ce qu'on appelle "l'industrie de l'édition du logiciel", une dénomination qui résume parfaitement son mode de fonctionnement, est en cours d'obsolescence. Aujourd'hui, il est de plus en plus possible de trouver quelqu'un sur un forum ou un proche capable d'apporter une solution logicielle à un problème logiciel.

Pour l'instant, c'est encore loin d'être envisageable par le commun des mortels, et est parfois même difficile pour un programmeur de profession. En pratique de nombreuses difficultés font obstacle: différentes applications utilisent différents langages parfois ésotériques ou abscons; il faut faire avec certains "aléas de fonctionnement"; il faut parfois poser maladroitement des questions en anglais sur des forums faute de documentation suffisante.

Et pourtant, ce monde idéal où un utilisateur pourrait modifier son logiciel soit par ces propres moyens, soit avec l'aide d'un autre, pour obtenir la fonction qu'il désire me paraît dans une certaine mesure possible. Mon expérience avec 4IM m' a donné cette impression. Forth est presque à l'opposé de cela, car c'est un langage ésotérique dont l'utilisation exige une connaissance plutôt pointue du fonctionnement d'un ordinateur et une rigueur des plus rigoureuses. Toutefois, pour qui aurait le courage de s'investir dans l'étude de 4IM, il y aurait la récompense d'accéder à quelques possibilités intéressantes, comme la construction d'une interface graphique, la communication en réseau, ou la construction d'univers animés en 3D (dans un version qui risque de prendre quelque temps à sortir...).

Il n'y a là rien de très extraordinaire; beaucoup de langages savent faire cela et bien plus, car il existe des librairies logicielles toutes faites qui réalisent ces fonctionnalités. Certaines librairies que j'ai utilisé sont si bien faites que, en faisant abstraction des connaissances nécessaires pour programmer en C/C++, n'importe qui pourrait l'utiliser.  

Contrairement aux fois précédentes, ce qui m'a motivé à imaginer un langage n'est pas une théorie mathématique ou logicielle glanée quelque part, mais plutôt des considérations sur les logiciels et leurs utilisateurs: les utilisateurs auront toujours des besoins bien particuliers auxquels les logiciels ne peuvent pas répondre, car trop spécifiques; des personnes sur internet ou autour de soi pourraient les aider à obtenir ce que l'on souhaite, mais ces bonnes volontés sont entravées par des difficultés techniques; des briques logicielles simples d'utilisation existent ou peuvent être créés pour réaliser des logiciels avec des fonctions élaborées.

C'est je pense un point de départ très différent de celui de la majorité des langages de programmation, qui partent du principe que leurs utilisateurs sont des programmeurs. Que les langages de programmation soient destinés aux programmeurs est une fausse évidence. Il existe des langages de programmation pour les non-programmeurs ou aspirants programmeurs (Basic par exemple).

Toutefois, beaucoup de ses langages pour être faciles d'accès sont trop simplistes pour faire des choses "sérieuses". Faire un programme nécessite un minimum de rigueur, de logique, d'aisance en maths, un goût pour la résolution de problèmes, autrement dit un esprit scientifique. Supposer que l'utilisateur du langage a ce profil est raisonnable, permet de ne pas sur-simplifier le langage et d'y introduire quelques concepts élaborés qui permettent de faire de "vrais" programmes.

La démocratisation d'Internet et l'explosion du logiciel libre a permis à plusieurs milliers de programmeurs, de concepteurs d'élaborer et de concrétiser autant d'idées si ce n'est plus. A tel point qu'il est difficile de ne pas trouver sur internet un logiciel réalisant une fonction particulière. Je me suis donc mis à la recherche d'un langage conçu dans le même but ou possédant les caractéristiques que j'estimais nécessaires pour l'atteindre. Je suis assez étonné de ne l'avoir pas trouvé.

Plutôt que d'énumérer de manière plus ou moins aride ces caractéristiques ici, il me paraît plus intéressant de faire la critique des différents langages que j'ai examiné. Ce sera l'objet de mes prochains articles.

lundi 12 janvier 2009

Hors-sujet : Zéro.

Le titre de ce blog vient de mon précédant "proto-blog" (http://astrobe.byethost31.com/hs.html).

En jettant un oeil à celui-là, force est de constater que presque tous les articles portent sur un même sujet, la programmation. Même en arguant que le sujet du site est 4IM, mon dialecte du langage Forth, le titre ne semblait pas tout à fait approprié.

Choisir le titre d'un blog est difficile si on est ni monomaniaque (auquel cas le titre s'articulera autour de la passion qui vous obsède), ni égocentrique (auquel cas il suffit de trouver un titre vous mettant suffisamment en valeur), on cherche avant tout un titre passe-partout, mais quand même un peu classe.

"Hors-sujet" est ce genre de titre: il ne véhicule rien de personnel ou de spécifique, mais il a quelque chose de sévère, sérieux et en même temps rebelle. Je pense que le souvenir de rédactions ou dissertations que l'on a cru brillantes ou que l'on a pris plaisir à rédiger, mais finalement frappées de cette condamnation, y est pour quelque chose.

Ce titre a un petit inconvénient: il faut que je choisisse un sujet dont je ne parlerai jamais, car pour pouvoir être hors-sujet, il faut bien définir un sujet. Le sujet de ce blog sera donc la définition du sujet de ce blog.