ÊTRE POPULAIRE
OriginalMai 2001
(Cet article a été écrit comme une sorte de plan d'affaires pour un nouveau langage. Il manque donc (parce qu'il prend pour acquis) la caractéristique la plus importante d'un bon langage de programmation : des abstractions très puissantes.)
Un ami m'a un jour dit à un éminent expert en systèmes d'exploitation qu'il voulait concevoir un très bon langage de programmation. L'expert lui a dit que ce serait une perte de temps, que les langages de programmation ne deviennent pas populaires ou impopulaires en fonction de leurs mérites, et donc, aussi bon que soit son langage, personne ne l'utiliserait. Du moins, c'est ce qui était arrivé au langage qu'il avait conçu.
Qu'est-ce qui rend un langage populaire ? Les langages populaires méritent-ils leur popularité ? Vaut-il la peine d'essayer de définir un bon langage de programmation ? Comment le feriez-vous ?
Je pense que les réponses à ces questions peuvent être trouvées en regardant les hackers, et en apprenant ce qu'ils veulent. Les langages de programmation sont pour les hackers, et un langage de programmation est bon en tant que langage de programmation (plutôt que, disons, un exercice de sémantique dénotationnelle ou de conception de compilateur) si et seulement si les hackers l'aiment.
1 La mécanique de la popularité
Il est vrai, certainement, que la plupart des gens ne choisissent pas les langages de programmation simplement en fonction de leurs mérites. La plupart des programmeurs se font dire quel langage utiliser par quelqu'un d'autre. Et pourtant, je pense que l'effet de ces facteurs externes sur la popularité des langages de programmation n'est pas aussi important qu'on le pense parfois. Je pense qu'un plus gros problème est que l'idée qu'un hacker se fait d'un bon langage de programmation est différente de celle de la plupart des concepteurs de langages.
Entre les deux, l'opinion du hacker est celle qui compte. Les langages de programmation ne sont pas des théorèmes. Ce sont des outils, conçus pour les gens, et ils doivent être conçus pour s'adapter aux forces et aux faiblesses humaines autant que les chaussures doivent être conçues pour les pieds humains. Si une chaussure pince lorsque vous la mettez, c'est une mauvaise chaussure, aussi élégante soit-elle en tant qu'œuvre de sculpture.
Il se peut que la majorité des programmeurs ne puissent pas distinguer un bon langage d'un mauvais. Mais ce n'est pas différent avec n'importe quel autre outil. Cela ne signifie pas que c'est une perte de temps d'essayer de concevoir un bon langage. Les hackers experts peuvent reconnaître un bon langage lorsqu'ils en voient un, et ils l'utiliseront. Les hackers experts sont une infime minorité, il est vrai, mais cette infime minorité écrit tous les bons logiciels, et leur influence est telle que le reste des programmeurs aura tendance à utiliser le langage qu'ils utilisent. Souvent, en effet, il ne s'agit pas simplement d'influence mais de commandement : souvent, les hackers experts sont les mêmes personnes qui, en tant que leurs patrons ou conseillers pédagogiques, disent aux autres programmeurs quel langage utiliser.
L'opinion des hackers experts n'est pas la seule force qui détermine la popularité relative des langages de programmation — les logiciels hérités (Cobol) et le battage médiatique (Ada, Java) jouent également un rôle — mais je pense que c'est la force la plus puissante à long terme. Étant donné une masse critique initiale et suffisamment de temps, un langage de programmation devient probablement aussi populaire qu'il le mérite. Et la popularité sépare encore plus les bons langages des mauvais, car la rétroaction des utilisateurs réels conduit toujours à des améliorations. Regardez combien n'importe quel langage populaire a changé au cours de sa vie. Perl et Fortran sont des cas extrêmes, mais même Lisp a beaucoup changé. Lisp 1.5 n'avait pas de macros, par exemple ; celles-ci ont évolué plus tard, après que les hackers du MIT aient passé quelques années à utiliser Lisp pour écrire de vrais programmes. [1]
Donc, qu'un langage doive ou non être bon pour être populaire, je pense qu'un langage doit être populaire pour être bon. Et il doit rester populaire pour rester bon. L'état de l'art en matière de langages de programmation ne reste pas immobile. Et pourtant, les Lisps que nous avons aujourd'hui sont encore à peu près ce qu'ils étaient au MIT au milieu des années 1980, parce que c'est la dernière fois que Lisp a eu une base d'utilisateurs suffisamment large et exigeante.
Bien sûr, les hackers doivent connaître un langage avant de pouvoir l'utiliser. Comment vont-ils entendre parler ? D'autres hackers. Mais il doit y avoir un groupe initial de hackers utilisant le langage pour que les autres puissent même en entendre parler. Je me demande quelle doit être la taille de ce groupe ; combien d'utilisateurs constituent une masse critique ? Au hasard, je dirais vingt. Si un langage avait vingt utilisateurs distincts, c'est-à-dire vingt utilisateurs qui ont décidé par eux-mêmes de l'utiliser, je le considérerais comme réel.
Y parvenir ne peut pas être facile. Je ne serais pas surpris si c'était plus difficile de passer de zéro à vingt que de vingt à mille. La meilleure façon d'obtenir ces vingt premiers utilisateurs est probablement d'utiliser un cheval de Troie : donner aux gens une application qu'ils veulent, qui se trouve être écrite dans le nouveau langage.
2 Facteurs externes
Commençons par reconnaître un facteur externe qui affecte la popularité d'un langage de programmation. Pour devenir populaire, un langage de programmation doit être le langage de script d'un système populaire. Fortran et Cobol étaient les langages de script des premiers mainframes IBM. C était le langage de script d'Unix, et donc, plus tard, Perl. Tcl est le langage de script de Tk. Java et Javascript sont destinés à être les langages de script des navigateurs Web.
Lisp n'est pas un langage massivement populaire parce qu'il n'est pas le langage de script d'un système massivement populaire. La popularité qu'il conserve date des années 1960 et 1970, lorsqu'il était le langage de script du MIT. Beaucoup des grands programmeurs de l'époque étaient associés au MIT à un moment donné. Et au début des années 1970, avant C, le dialecte Lisp du MIT, appelé MacLisp, était l'un des seuls langages de programmation qu'un hacker sérieux voudrait utiliser.
Aujourd'hui, Lisp est le langage de script de deux systèmes modérément populaires, Emacs et Autocad, et pour cette raison, je soupçonne que la plupart de la programmation Lisp effectuée aujourd'hui est effectuée en Emacs Lisp ou AutoLisp.
Les langages de programmation n'existent pas en vase clos. Hacker est un verbe transitif — les hackers piratent généralement quelque chose — et dans la pratique, les langages sont jugés par rapport à ce qu'ils sont utilisés pour pirater. Donc, si vous voulez concevoir un langage populaire, vous devez soit fournir plus qu'un langage, soit concevoir votre langage pour remplacer le langage de script d'un système existant.
Common Lisp est impopulaire en partie parce qu'il est orphelin. Il était à l'origine livré avec un système à pirater : la Lisp Machine. Mais les Lisp Machines (avec les ordinateurs parallèles) ont été écrasées par la puissance croissante des processeurs à usage général dans les années 1980. Common Lisp aurait pu rester populaire s'il avait été un bon langage de script pour Unix. C'est, hélas, un langage atrocement mauvais.
Une façon de décrire cette situation est de dire qu'un langage n'est pas jugé sur ses propres mérites. Un autre point de vue est qu'un langage de programmation n'est pas vraiment un langage de programmation s'il n'est pas aussi le langage de script de quelque chose. Cela ne semble injuste que si cela arrive par surprise. Je pense que ce n'est pas plus injuste que de s'attendre à ce qu'un langage de programmation ait, disons, une implémentation. Cela fait simplement partie de ce qu'est un langage de programmation.
Un langage de programmation a besoin d'une bonne implémentation, bien sûr, et celle-ci doit être gratuite. Les entreprises paieront pour les logiciels, mais les individus les hackers ne le feront pas, et ce sont les hackers qu'il faut attirer.
Un langage doit également avoir un livre à son sujet. Le livre doit être fin, bien écrit et plein de bons exemples. K&R est l'idéal ici. En ce moment, je dirais presque qu'un langage doit avoir un livre publié par O'Reilly. C'est en train de devenir le test de l'importance pour les hackers.
Il devrait également y avoir une documentation en ligne. En fait, le livre peut commencer comme une documentation en ligne. Mais je ne pense pas que les livres physiques soient encore dépassés. Leur format est pratique, et la censure de facto imposée par les éditeurs est un filtre utile, bien qu'imparfait. Les librairies sont l'un des endroits les plus importants pour apprendre à connaître les nouveaux langages.
3 Brève
Étant donné que vous pouvez fournir les trois choses dont tout langage a besoin — une implémentation gratuite, un livre et quelque chose à pirater — comment faites-vous un langage que les hackers apprécieront ?
Une chose que les hackers aiment, c'est la brièveté. Les hackers sont paresseux, de la même manière que les mathématiciens et les architectes modernistes sont paresseux : ils détestent tout ce qui est superflu. Il ne serait pas loin de la vérité de dire qu'un hacker sur le point d'écrire un programme décide quel langage utiliser, au moins inconsciemment, en fonction du nombre total de caractères qu'il devra taper. Si ce n'est pas exactement comme ça que les hackers pensent, un concepteur de langage ferait bien d'agir comme si c'était le cas.
C'est une erreur d'essayer de dorloter l'utilisateur avec des expressions longues qui sont censées ressembler à l'anglais. Cobol est célèbre pour ce défaut. Un hacker considérerait qu'on lui demande d'écrire
add x to y giving z
au lieu de
z = x+y
comme quelque chose entre une insulte à son intelligence et un péché contre Dieu.
On a parfois dit que Lisp devrait utiliser first et rest au lieu de car et cdr, car cela rendrait les programmes plus faciles à lire. Peut-être pour les deux premières heures. Mais un hacker peut apprendre assez rapidement que car signifie le premier élément d'une liste et cdr signifie le reste. Utiliser first et rest signifie 50 % de frappe en plus. Et ils sont également de longueurs différentes, ce qui signifie que les arguments ne seront pas alignés lorsqu'ils sont appelés, comme car et cdr le sont souvent, dans des lignes successives. J'ai constaté que l'alignement du code sur la page a beaucoup d'importance. Je peux à peine lire du code Lisp lorsqu'il est mis en forme dans une police à largeur variable, et des amis disent que c'est vrai pour d'autres langages aussi.
La brièveté est l'un des endroits où les langages fortement typés perdent. Toutes choses étant égales par ailleurs, personne ne veut commencer un programme avec un tas de déclarations. Tout ce qui peut être implicite doit l'être.
Les jetons individuels doivent également être courts. Perl et Common Lisp occupent des pôles opposés sur cette question. Les programmes Perl peuvent être presque cryptiquement denses, tandis que les noms des opérateurs Common Lisp intégrés sont comiquement longs. Les concepteurs de Common Lisp s'attendaient probablement à ce que les utilisateurs aient des éditeurs de texte qui taperaient ces longs noms pour eux. Mais le coût d'un long nom n'est pas seulement le coût de sa frappe. Il y a aussi le coût de sa lecture, et le coût de l'espace qu'il prend sur votre écran.
4 Hackabilité
Il y a une chose plus importante que la brièveté pour un hacker : être capable de faire ce qu'il veut. Dans l'histoire des langages de programmation, une quantité surprenante d'efforts a été consacrée à empêcher les programmeurs de faire des choses considérées comme impropres. C'est un plan dangereusement présomptueux. Comment le concepteur de langage peut-il savoir ce que le programmeur va devoir faire ? Je pense que les concepteurs de langage feraient mieux de considérer leur utilisateur cible comme un génie qui aura besoin de faire des choses qu'ils n'ont jamais anticipées, plutôt que comme un maladroit qui a besoin d'être protégé de lui-même. Le maladroit se tirera une balle dans le pied de toute façon. Vous pouvez le sauver de se référer à des variables dans un autre package, mais vous ne pouvez pas le sauver de l'écriture d'un programme mal conçu pour résoudre le mauvais problème, et de prendre une éternité à le faire.
Les bons programmeurs veulent souvent faire des choses dangereuses et peu recommandables. Par peu recommandables, j'entends des choses qui vont derrière la façade sémantique que le langage essaie de présenter : obtenir la représentation interne d'une abstraction de haut niveau, par exemple. Les hackers aiment pirater, et pirater signifie entrer dans les choses et remettre en question le concepteur original.
Laissez-vous remettre en question. Lorsque vous créez un outil, les gens l'utilisent de manière inattendue, et c'est particulièrement vrai pour un outil très articulé comme un langage de programmation. De nombreux hackers voudront modifier votre modèle sémantique d'une manière que vous n'avez jamais imaginée. Je dis, laissez-les ; donnez au programmeur accès à autant de choses internes que possible sans mettre en danger les systèmes d'exécution comme le ramasse-miettes.
En Common Lisp, j'ai souvent voulu itérer sur les champs d'une structure — pour éliminer les références à un objet supprimé, par exemple, ou trouver des champs qui ne sont pas initialisés. Je sais que les structures ne sont que des vecteurs en dessous. Et pourtant, je ne peux pas écrire une fonction à usage général que je peux appeler sur n'importe quelle structure. Je ne peux accéder aux champs que par leur nom, parce que c'est ce que la structure est censée signifier.
Un hacker peut ne vouloir subvertir le modèle prévu des choses qu'une fois ou deux dans un grand programme. Mais quelle différence cela fait de pouvoir le faire. Et ce n'est peut-être pas qu'une question de résolution d'un problème. Il y a aussi un certain plaisir ici. Les hackers partagent le plaisir secret du chirurgien à fouiller dans les entrailles grossières, le plaisir secret de l'adolescent à faire éclater des boutons. [2] Pour les garçons, du moins, certains types d'horreurs sont fascinants. Le magazine Maxim publie un volume annuel de photographies, contenant un mélange de pin-ups et d'accidents macabres. Ils connaissent leur public.
Historiquement, Lisp a été bon pour laisser les hackers faire ce qu'ils veulent. Le politiquement correct de Common Lisp est une aberration. Les premiers Lisps vous laissaient mettre les mains sur tout. Une bonne partie de cet esprit est, heureusement, préservée dans les macros. Quelle merveilleuse chose, de pouvoir faire des transformations arbitraires sur le code source.
Les macros classiques sont un véritable outil de hacker — simples, puissantes et dangereuses. Il est si facile de comprendre ce qu'elles font : vous appelez une fonction sur les arguments de la macro, et tout ce qu'elle renvoie est inséré à la place de l'appel de macro. Les macros hygiéniques incarnent le principe opposé. Elles essaient de vous protéger de la compréhension de ce qu'elles font. Je n'ai jamais entendu expliquer les macros hygiéniques en une phrase. Et elles sont un exemple classique des dangers de décider ce que les programmeurs sont autorisés à vouloir. Les macros hygiéniques sont censées me protéger de la capture de variables, entre autres choses, mais la capture de variables est exactement ce que je veux dans certaines macros.
Un très bon langage devrait être à la fois propre et sale : proprement conçu, avec un petit noyau d'opérateurs bien compris et hautement orthogonaux, mais sale dans le sens où il laisse les hackers faire ce qu'ils veulent. C'est comme ça que C est. C'était aussi le cas des premiers Lisps. Un véritable langage de hacker aura toujours un caractère légèrement louche.
Un bon langage de programmation devrait avoir des fonctionnalités qui font que le genre de personnes qui utilisent l'expression "ingénierie logicielle" secouent la tête avec désapprobation. À l'autre extrémité du continuum se trouvent des langages comme Ada et Pascal, des modèles de bienséance qui sont bons pour l'enseignement et pas grand-chose d'autre.
5 Programmes jetables
Pour être attrayant pour les hackers, un langage doit être bon pour écrire les types de programmes qu'ils veulent écrire. Et cela signifie, peut-être de manière surprenante, qu'il doit être bon pour écrire des programmes jetables.
Un programme jetable est un programme que vous écrivez rapidement pour une tâche limitée : un programme pour automatiser une tâche d'administration système, ou générer des données de test pour une simulation, ou convertir des données d'un format à un autre. Ce qui est surprenant avec les programmes jetables, c'est que, comme les bâtiments "temporaires" construits dans tant d'universités américaines pendant la Seconde Guerre mondiale, ils ne sont souvent pas jetés. Beaucoup évoluent pour devenir de vrais programmes, avec de vraies fonctionnalités et de vrais utilisateurs.
J'ai le sentiment que les meilleurs grands programmes commencent leur vie de cette façon, plutôt que d'être conçus grands dès le départ, comme le barrage Hoover. C'est terrifiant de construire quelque chose de grand à partir de zéro. Lorsque les gens entreprennent un projet trop grand, ils sont dépassés. Le projet est soit bloqué, soit le résultat est stérile et en bois : un centre commercial plutôt qu'un vrai centre-ville, Brasilia plutôt que Rome, Ada plutôt que C.
Une autre façon d'obtenir un grand programme est de commencer par un programme jetable et de continuer à l'améliorer. Cette approche est moins intimidante, et la conception du programme bénéficie de l'évolution. Je pense que, si l'on regardait, cela se révélerait être la façon dont la plupart des grands programmes ont été développés. Et ceux qui ont évolué de cette façon sont probablement encore écrits dans le langage dans lequel ils ont été écrits pour la première fois, car il est rare qu'un programme soit porté, sauf pour des raisons politiques. Et donc, paradoxalement, si vous voulez faire un langage qui est utilisé pour les grands systèmes, vous devez le rendre bon pour écrire des programmes jetables, car c'est de là que viennent les grands systèmes.
Perl est un exemple frappant de cette idée. Il n'a pas seulement été conçu pour écrire des programmes jetables, mais était à peu près un programme jetable lui-même. Perl a commencé sa vie comme une collection d'utilitaires pour générer des rapports, et n'a évolué pour devenir un langage de programmation que lorsque les programmes jetables que les gens écrivaient dans ce langage sont devenus plus grands. Ce n'est qu'avec Perl 5 (si tant est que ce soit) que le langage est devenu adapté à l'écriture de programmes sérieux, et pourtant il était déjà massivement populaire.
Qu'est-ce qui rend un langage bon pour les programmes jetables ? Pour commencer, il doit être facilement disponible. Un programme jetable est quelque chose que vous vous attendez à écrire en une heure. Le langage doit donc probablement être déjà installé sur l'ordinateur que vous utilisez. Il ne peut pas être quelque chose que vous devez installer avant de l'utiliser. Il doit être là. C était là parce qu'il était livré avec le système d'exploitation. Perl était là parce qu'il était à l'origine un outil pour les administrateurs système, et le vôtre l'avait déjà installé.
Être disponible signifie plus que d'être installé, cependant. Un langage interactif, avec une interface en ligne de commande, est plus disponible qu'un langage que vous devez compiler et exécuter séparément. Un langage de programmation populaire doit être interactif, et démarrer rapidement.
Une autre chose que vous voulez dans un programme jetable, c'est la brièveté. La brièveté est toujours attrayante pour les hackers, et jamais plus que dans un programme qu'ils s'attendent à réaliser en une heure.
6 Bibliothèques
Bien sûr, la brièveté ultime est d'avoir le programme déjà écrit pour vous et de simplement l'appeler. Et cela nous amène à ce que je pense être une caractéristique de plus en plus importante des langages de programmation : les fonctions de bibliothèque. Perl gagne parce qu'il possède de vastes bibliothèques pour manipuler les chaînes de caractères. Cette classe de fonctions de bibliothèque est particulièrement importante pour les programmes jetables, qui sont souvent écrits à l'origine pour convertir ou extraire des données. De nombreux programmes Perl commencent probablement comme un simple couple d'appels de bibliothèque collés ensemble.
Je pense qu'une grande partie des progrès qui se produiront dans les langages de programmation au cours des cinquante prochaines années auront à voir avec les fonctions de bibliothèque. Je pense que les langages de programmation futurs auront des bibliothèques aussi soigneusement conçues que le langage de base. La conception des langages de programmation ne portera pas sur la question de savoir s'il faut rendre votre langage fortement ou faiblement typé, ou orienté objet, ou fonctionnel, ou quoi que ce soit, mais sur la façon de concevoir de superbes bibliothèques. Le genre de concepteurs de langages qui aiment réfléchir à la façon de concevoir des systèmes de types pourraient frémir à cette idée. C'est presque comme écrire des applications ! Dommage. Les langages sont pour les programmeurs, et les bibliothèques sont ce dont les programmeurs ont besoin.
Il est difficile de concevoir de bonnes bibliothèques. Ce n'est pas simplement une question d'écrire beaucoup de code. Une fois que les bibliothèques deviennent trop volumineuses, il peut parfois prendre plus de temps pour trouver la fonction dont vous avez besoin que pour écrire le code vous-même. Les bibliothèques doivent être conçues en utilisant un petit ensemble d'opérateurs orthogonaux, tout comme le langage de base. Il devrait être possible pour le programmeur de deviner quel appel de bibliothèque fera ce dont il a besoin.
Les bibliothèques sont un des points faibles de Common Lisp. Il n'y a que des bibliothèques rudimentaires pour manipuler les chaînes de caractères, et presque aucune pour communiquer avec le système d'exploitation. Pour des raisons historiques, Common Lisp essaie de faire semblant que le système d'exploitation n'existe pas. Et parce que vous ne pouvez pas communiquer avec le système d'exploitation, il est peu probable que vous puissiez écrire un programme sérieux en utilisant uniquement les opérateurs intégrés de Common Lisp. Vous devez également utiliser des hacks spécifiques à l'implémentation, et en pratique, ceux-ci ne vous donnent généralement pas tout ce que vous voulez. Les hackers penseraient beaucoup plus positivement de Lisp si Common Lisp avait de puissantes bibliothèques de chaînes de caractères et un bon support du système d'exploitation.
7 Syntaxe
Un langage avec la syntaxe de Lisp, ou plus précisément, l'absence de syntaxe, pourrait-il jamais devenir populaire ? Je ne connais pas la réponse à cette question. Je pense que la syntaxe n'est pas la principale raison pour laquelle Lisp n'est pas actuellement populaire. Common Lisp a des problèmes plus graves que sa syntaxe peu familière. Je connais plusieurs programmeurs qui sont à l'aise avec la syntaxe préfixée et qui pourtant utilisent Perl par défaut, car il possède de puissantes bibliothèques de chaînes de caractères et peut communiquer avec le système d'exploitation.
Il y a deux problèmes possibles avec la notation préfixée : qu'elle soit peu familière aux programmeurs et qu'elle ne soit pas assez dense. La sagesse conventionnelle dans le monde de Lisp est que le premier problème est le vrai. Je n'en suis pas si sûr. Oui, la notation préfixée fait paniquer les programmeurs ordinaires. Mais je ne pense pas que l'opinion des programmeurs ordinaires compte. Les langages deviennent populaires ou impopulaires en fonction de ce que les hackers experts pensent d'eux, et je pense que les hackers experts pourraient être en mesure de gérer la notation préfixée. La syntaxe de Perl peut être assez incompréhensible, mais cela n'a pas empêché la popularité de Perl. Si quoi que ce soit, cela a peut-être contribué à favoriser un culte de Perl.
Un problème plus grave est la diffusion de la notation préfixée. Pour les hackers experts, c'est vraiment un problème. Personne ne veut écrire (aref a x y) lorsqu'il peut écrire a[x,y].
Dans ce cas particulier, il existe un moyen de contourner le problème. Si nous traitons les structures de données comme s'il s'agissait de fonctions sur des index, nous pourrions écrire (a x y) à la place, ce qui est encore plus court que la forme Perl. Des astuces similaires peuvent raccourcir d'autres types d'expressions.
Nous pouvons supprimer (ou rendre facultatives) de nombreuses parenthèses en rendant l'indentation significative. C'est comme ça que les programmeurs lisent le code de toute façon : lorsque l'indentation dit une chose et que les délimiteurs en disent une autre, nous nous fions à l'indentation. Traiter l'indentation comme significative éliminerait cette source courante de bogues tout en rendant les programmes plus courts.
Parfois, la syntaxe infixée est plus facile à lire. C'est particulièrement vrai pour les expressions mathématiques. J'utilise Lisp toute ma vie de programmeur et je ne trouve toujours pas les expressions mathématiques préfixées naturelles. Et pourtant, c'est pratique, surtout lorsque vous générez du code, d'avoir des opérateurs qui prennent un nombre quelconque d'arguments. Donc, si nous avons une syntaxe infixée, elle devrait probablement être implémentée comme une sorte de macro de lecture.
Je ne pense pas que nous devrions nous opposer religieusement à l'introduction de la syntaxe dans Lisp, tant qu'elle se traduit de manière bien comprise en expressions S sous-jacentes. Il y a déjà beaucoup de syntaxe dans Lisp. Ce n'est pas nécessairement mauvais d'en introduire davantage, tant que personne n'est obligé de l'utiliser. En Common Lisp, certains délimiteurs sont réservés au langage, ce qui suggère qu'au moins certains des concepteurs avaient l'intention d'avoir plus de syntaxe à l'avenir.
L'un des éléments de syntaxe les plus scandaleusement non-lispiens de Common Lisp se produit dans les chaînes de formatage ; format est un langage à part entière, et ce langage n'est pas Lisp. S'il y avait un plan pour introduire plus de syntaxe dans Lisp, les spécificateurs de format pourraient être inclus dans celui-ci. Ce serait une bonne chose si les macros pouvaient générer des spécificateurs de format de la même manière qu'elles génèrent tout autre type de code.
Un éminent hacker Lisp m'a dit que son exemplaire de CLTL s'ouvre à la section format. Le mien aussi. Cela indique probablement une marge de progression. Cela peut aussi signifier que les programmes font beaucoup d'E/S.
8 Efficacité
Un bon langage, comme chacun le sait, devrait générer du code rapide. Mais en pratique, je ne pense pas que le code rapide provienne principalement des choses que vous faites dans la conception du langage. Comme Knuth l'a fait remarquer il y a longtemps, la vitesse ne compte que dans certains goulots d'étranglement critiques. Et comme de nombreux programmeurs l'ont observé depuis, on se trompe très souvent sur l'emplacement de ces goulots d'étranglement.
Donc, en pratique, la façon d'obtenir du code rapide est d'avoir un très bon profileur, plutôt que, par exemple, de rendre le langage fortement typé. Vous n'avez pas besoin de connaître le type de chaque argument dans chaque appel du programme. Vous devez être en mesure de déclarer les types d'arguments dans les goulots d'étranglement. Et plus encore, vous devez être en mesure de déterminer où se trouvent les goulots d'étranglement.
Une plainte que les gens ont eue avec Lisp est qu'il est difficile de dire ce qui est coûteux. Cela pourrait être vrai. Cela pourrait aussi être inévitable, si vous voulez avoir un langage très abstrait. Et de toute façon, je pense qu'un bon profilage contribuerait grandement à résoudre le problème : vous apprendriez rapidement ce qui est coûteux.
Une partie du problème est sociale. Les concepteurs de langages aiment écrire des compilateurs rapides. C'est comme ça qu'ils mesurent leurs compétences. Ils considèrent le profileur comme un ajout, au mieux. Mais en pratique, un bon profileur peut faire plus pour améliorer la vitesse des programmes réels écrits dans le langage qu'un compilateur qui génère du code rapide. Ici encore, les concepteurs de langages sont quelque peu en décalage avec leurs utilisateurs. Ils font un très bon travail pour résoudre un problème légèrement erroné.
Ce serait peut-être une bonne idée d'avoir un profileur actif — pour pousser les données de performance vers le programmeur au lieu d'attendre qu'il vienne les demander. Par exemple, l'éditeur pourrait afficher les goulots d'étranglement en rouge lorsque le programmeur modifie le code source. Une autre approche serait de représenter d'une manière ou d'une autre ce qui se passe dans les programmes en cours d'exécution. Ce serait un gain particulièrement important dans les applications basées sur des serveurs, où vous avez beaucoup de programmes en cours d'exécution à examiner. Un profileur actif pourrait montrer graphiquement ce qui se passe en mémoire pendant l'exécution d'un programme, ou même émettre des sons qui indiquent ce qui se passe.
Le son est un bon indice des problèmes. Dans un endroit où j'ai travaillé, nous avions un grand tableau de cadrans montrant ce qui se passait sur nos serveurs Web. Les aiguilles étaient déplacées par de petits servomoteurs qui émettaient un léger bruit lorsqu'ils tournaient. Je ne pouvais pas voir le tableau depuis mon bureau, mais j'ai constaté que je pouvais dire immédiatement, par le son, quand il y avait un problème avec un serveur.
Il pourrait même être possible d'écrire un profileur qui détecterait automatiquement les algorithmes inefficaces. Je ne serais pas surpris si certains schémas d'accès à la mémoire s'avéraient être des signes sûrs de mauvais algorithmes. S'il y avait un petit bonhomme qui courait dans l'ordinateur en exécutant nos programmes, il aurait probablement une histoire aussi longue et plaintive à raconter sur son travail qu'un employé du gouvernement fédéral. J'ai souvent l'impression d'envoyer le processeur sur de nombreuses chasses aux oies sauvages, mais je n'ai jamais eu un bon moyen de regarder ce qu'il fait.
Un certain nombre de Lisps compilent maintenant en bytecode, qui est ensuite exécuté par un interpréteur. Cela est généralement fait pour rendre l'implémentation plus facile à porter, mais cela pourrait être une fonctionnalité de langage utile. Ce serait peut-être une bonne idée de faire du bytecode une partie officielle du langage et de permettre aux programmeurs d'utiliser du bytecode en ligne dans les goulots d'étranglement. Alors, ces optimisations seraient également portables.
La nature de la vitesse, telle que perçue par l'utilisateur final, est peut-être en train de changer. Avec l'essor des applications basées sur des serveurs, de plus en plus de programmes peuvent s'avérer liés aux E/S. Il vaudra la peine de rendre les E/S rapides. Le langage peut aider avec des mesures simples comme des fonctions de sortie formatées simples et rapides, et aussi avec des changements structurels profonds comme la mise en cache et les objets persistants.
Les utilisateurs sont intéressés par le temps de réponse. Mais un autre type d'efficacité sera de plus en plus important : le nombre d'utilisateurs simultanés que vous pouvez prendre en charge par processeur. Bon nombre des applications intéressantes qui seront écrites dans un avenir proche seront basées sur des serveurs, et le nombre d'utilisateurs par serveur est la question cruciale pour toute personne hébergeant de telles applications. Dans le coût en capital d'une entreprise offrant une application basée sur un serveur, c'est le diviseur.
Pendant des années, l'efficacité n'a pas beaucoup compté dans la plupart des applications grand public. Les développeurs ont pu supposer que chaque utilisateur aurait un processeur de plus en plus puissant sur son bureau. Et selon la loi de Parkinson, les logiciels se sont développés pour utiliser les ressources disponibles. Cela changera avec les applications basées sur des serveurs. Dans ce monde, le matériel et les logiciels seront fournis ensemble. Pour les entreprises qui proposent des applications basées sur des serveurs, le nombre d'utilisateurs qu'elles peuvent prendre en charge par serveur fera une très grande différence pour leurs résultats.
Dans certaines applications, le processeur sera le facteur limitant, et la vitesse d'exécution sera la chose la plus importante à optimiser. Mais souvent, la mémoire sera la limite ; le nombre d'utilisateurs simultanés sera déterminé par la quantité de mémoire dont vous avez besoin pour les données de chaque utilisateur. Le langage peut également aider ici. Un bon support pour les threads permettra à tous les utilisateurs de partager un seul tas. Il peut également être utile d'avoir des objets persistants et/ou un support au niveau du langage pour le chargement paresseux.
9 Temps
Le dernier ingrédient dont un langage populaire a besoin est le temps. Personne ne veut écrire des programmes dans un langage qui pourrait disparaître, comme le font tant de langages de programmation. Ainsi, la plupart des hackers auront tendance à attendre qu'un langage existe depuis quelques années avant même d'envisager de l'utiliser.
Les inventeurs de nouvelles choses merveilleuses sont souvent surpris de découvrir cela, mais il faut du temps pour faire passer un message aux gens. Un de mes amis ne fait presque jamais quelque chose la première fois que quelqu'un lui demande. Il sait que les gens demandent parfois des choses qu'ils finissent par ne pas vouloir. Pour éviter de perdre son temps, il attend la troisième ou la quatrième fois qu'on lui demande de faire quelque chose ; à ce moment-là, celui qui lui demande est peut-être assez énervé, mais au moins, il veut probablement vraiment ce qu'il demande.
La plupart des gens ont appris à faire un type de filtrage similaire sur les nouvelles choses dont ils entendent parler. Ils ne commencent même pas à prêter attention avant d'avoir entendu parler de quelque chose dix fois. Ils sont parfaitement justifiés : la majorité des nouveautés sont effectivement une perte de temps et finissent par disparaître. En retardant l'apprentissage de VRML, j'ai évité d'avoir à l'apprendre du tout.
Ainsi, toute personne qui invente quelque chose de nouveau doit s'attendre à répéter son message pendant des années avant que les gens ne commencent à le comprendre. Nous avons écrit ce qui était, à ma connaissance, la première application basée sur un serveur Web, et il nous a fallu des années pour faire comprendre aux gens qu'elle n'avait pas besoin d'être téléchargée. Ce n'est pas qu'ils étaient stupides. Ils nous avaient simplement mis sur la touche.
La bonne nouvelle, c'est que la simple répétition résout le problème. Tout ce que vous avez à faire est de continuer à raconter votre histoire, et les gens finiront par commencer à l'entendre. Ce n'est pas quand les gens remarquent que vous êtes là qu'ils prêtent attention ; c'est quand ils remarquent que vous êtes toujours là.
C'est tant mieux que cela prenne généralement un certain temps pour prendre de l'ampleur. La plupart des technologies évoluent beaucoup même après leur lancement — les langages de programmation en particulier. Rien ne pourrait être mieux, pour une nouvelle technologie, que quelques années d'utilisation uniquement par un petit nombre d'adoptants précoces. Les adoptants précoces sont sophistiqués et exigeants, et ils éliminent rapidement les défauts qui subsistent dans votre technologie. Lorsque vous n'avez que quelques utilisateurs, vous pouvez être en contact étroit avec tous. Et les adoptants précoces sont indulgents lorsque vous améliorez votre système, même si cela provoque des pannes.
Il existe deux façons d'introduire une nouvelle technologie : la méthode de croissance organique et la méthode du big bang. La méthode de croissance organique est illustrée par la startup classique de garage sous-financée et improvisée. Deux gars, travaillant dans l'obscurité, développent une nouvelle technologie. Ils la lancent sans marketing et n'ont initialement que quelques utilisateurs (fanatiquement dévoués). Ils continuent à améliorer la technologie, et pendant ce temps, leur base d'utilisateurs se développe par le bouche-à-oreille. Avant qu'ils ne s'en rendent compte, ils sont grands.
L'autre approche, la méthode du big bang, est illustrée par la startup soutenue par des fonds de capital-risque et fortement commercialisée. Ils se précipitent pour développer un produit, le lancent avec une grande publicité et ont immédiatement (ils l'espèrent) une large base d'utilisateurs.
En général, les gars du garage envient les gars du big bang. Les gars du big bang sont lisses, confiants et respectés par les fonds de capital-risque. Ils peuvent se permettre le meilleur de tout, et la campagne de relations publiques entourant le lancement a pour effet secondaire de faire d'eux des célébrités. Les gars de la croissance organique, assis dans leur garage, se sentent pauvres et mal-aimés. Et pourtant, je pense qu'ils ont souvent tort de se sentir désolés pour eux-mêmes. La croissance organique semble produire une meilleure technologie et des fondateurs plus riches que la méthode du big bang. Si vous regardez les technologies dominantes d'aujourd'hui, vous constaterez que la plupart d'entre elles ont connu une croissance organique.
Ce modèle ne s'applique pas seulement aux entreprises. Vous le voyez aussi dans la recherche sponsorisée. Multics et Common Lisp étaient des projets de type big bang, et Unix et MacLisp étaient des projets de croissance organique.
10 Reconception
"La meilleure écriture est la réécriture", a écrit E. B. White. Tout bon écrivain le sait, et c'est vrai pour les logiciels aussi. La partie la plus importante de la conception est la reconception. Les langages de programmation, en particulier, ne sont pas assez remaniés.
Pour écrire un bon logiciel, vous devez garder simultanément deux idées opposées dans votre tête. Vous avez besoin de la foi naïve du jeune hacker en ses capacités, et en même temps du scepticisme du vétéran. Vous devez être capable de penser à quel point cela peut être difficile ? avec une moitié de votre cerveau tout en pensant cela ne fonctionnera jamais avec l'autre.
L'astuce est de réaliser qu'il n'y a pas de véritable contradiction ici. Vous voulez être optimiste et sceptique à propos de deux choses différentes. Vous devez être optimiste quant à la possibilité de résoudre le problème, mais sceptique quant à la valeur de la solution que vous avez obtenue jusqu'à présent.
Les personnes qui font du bon travail pensent souvent que ce sur quoi elles travaillent n'est pas bon. Les autres voient ce qu'ils ont fait et sont remplis d'émerveillement, mais le créateur est plein d'inquiétudes. Ce modèle n'est pas une coïncidence : c'est l'inquiétude qui a rendu le travail bon.
Si vous pouvez maintenir l'espoir et l'inquiétude en équilibre, ils feront avancer un projet de la même manière que vos deux jambes font avancer un vélo. Dans la première phase du moteur d'innovation à deux cycles, vous travaillez furieusement sur un problème, inspiré par votre confiance que vous serez en mesure de le résoudre. Dans la deuxième phase, vous regardez ce que vous avez fait à la lumière froide du matin, et vous voyez très clairement tous ses défauts. Mais tant que votre esprit critique ne l'emporte pas sur votre espoir, vous serez en mesure de regarder votre système, certes incomplet, et de penser, à quel point cela peut être difficile pour aller jusqu'au bout ?, poursuivant ainsi le cycle.
Il est délicat de maintenir les deux forces en équilibre. Chez les jeunes hackers, l'optimisme prédomine. Ils produisent quelque chose, sont convaincus que c'est génial, et ne l'améliorent jamais. Chez les vieux hackers, le scepticisme prédomine, et ils n'osent même pas entreprendre des projets ambitieux.
Tout ce que vous pouvez faire pour maintenir le cycle de reconception est bon. La prose peut être réécrite encore et encore jusqu'à ce que vous en soyez satisfait. Mais les logiciels, en règle générale, ne sont pas assez remaniés. La prose a des lecteurs, mais les logiciels ont des utilisateurs. Si un écrivain réécrit un essai, les personnes qui ont lu la vieille version sont peu susceptibles de se plaindre que leurs pensées ont été brisées par une incompatibilité nouvellement introduite.
Les utilisateurs sont une arme à double tranchant. Ils peuvent vous aider à améliorer votre langage, mais ils peuvent aussi vous dissuader de l'améliorer. Choisissez donc vos utilisateurs avec soin, et soyez lent à augmenter leur nombre. Avoir des utilisateurs, c'est comme l'optimisation : la sage conduite est de la retarder. De plus, en règle générale, vous pouvez à tout moment vous permettre de changer plus que vous ne le pensez. Introduire un changement, c'est comme enlever un pansement : la douleur est un souvenir presque dès que vous la ressentez.
Tout le monde sait qu'il n'est pas bon d'avoir un langage conçu par un comité. Les comités produisent de mauvaises conceptions. Mais je pense que le pire danger des comités est qu'ils interfèrent avec la reconception. Il faut tellement de travail pour introduire des changements que personne ne veut s'en donner la peine. Tout ce qu'un comité décide a tendance à rester ainsi, même si la plupart des membres ne l'aiment pas.
Même un comité de deux personnes gêne la refonte. Cela se produit particulièrement dans les interfaces entre des morceaux de logiciels écrits par deux personnes différentes. Pour modifier l'interface, les deux doivent se mettre d'accord pour la modifier en même temps. Et donc les interfaces ont tendance à ne pas changer du tout, ce qui est un problème car elles ont tendance à être l'une des parties les plus ad hoc de tout système.
Une solution ici pourrait être de concevoir des systèmes de sorte que les interfaces soient horizontales au lieu de verticales - de sorte que les modules soient toujours des strates d'abstraction empilées verticalement. Ensuite, l'interface aura tendance à être détenue par l'une d'entre elles. Le niveau inférieur de deux niveaux sera soit un langage dans lequel le niveau supérieur est écrit, auquel cas le niveau inférieur sera propriétaire de l'interface, soit il sera un esclave, auquel cas l'interface peut être dictée par le niveau supérieur.
11 Lisp
Tout cela implique qu'il y a de l'espoir pour un nouveau Lisp. Il y a de l'espoir pour tout langage qui donne aux hackers ce qu'ils veulent, y compris Lisp. Je pense que nous avons peut-être fait une erreur en pensant que les hackers sont rebutés par l'étrangeté de Lisp. Cette illusion réconfortante peut nous avoir empêchés de voir le vrai problème avec Lisp, ou du moins Common Lisp, qui est qu'il est nul pour faire ce que les hackers veulent faire. Un langage de hacker a besoin de bibliothèques puissantes et de quelque chose à pirater. Common Lisp n'a ni l'un ni l'autre. Un langage de hacker est concis et piratable. Common Lisp ne l'est pas.
La bonne nouvelle est que ce n'est pas Lisp qui est nul, mais Common Lisp. Si nous pouvons développer un nouveau Lisp qui soit un véritable langage de hacker, je pense que les hackers l'utiliseront. Ils utiliseront n'importe quel langage qui fait le travail. Tout ce que nous avons à faire est de nous assurer que ce nouveau Lisp fait un travail important mieux que les autres langages.
L'histoire offre un certain encouragement. Au fil du temps, les nouveaux langages de programmation successifs ont repris de plus en plus de fonctionnalités de Lisp. Il ne reste plus grand-chose à copier avant que le langage que vous avez créé ne soit Lisp. Le dernier langage à la mode, Python, est un Lisp dilué avec une syntaxe infixe et pas de macros. Un nouveau Lisp serait un pas naturel dans cette progression.
Je pense parfois que ce serait un bon stratagème marketing d'appeler cela une version améliorée de Python. Cela semble plus branché que Lisp. Pour beaucoup de gens, Lisp est un langage d'IA lent avec beaucoup de parenthèses. La biographie officielle de Fritz Kunze évite soigneusement de mentionner le mot L. Mais je suppose que nous ne devrions pas avoir peur d'appeler le nouveau Lisp Lisp. Lisp a toujours beaucoup de respect latent parmi les meilleurs hackers - ceux qui ont suivi le cours 6.001 et l'ont compris, par exemple. Et ce sont les utilisateurs que vous devez gagner.
Dans "Comment devenir un hacker", Eric Raymond décrit Lisp comme quelque chose comme le latin ou le grec - un langage que vous devriez apprendre comme un exercice intellectuel, même si vous ne l'utiliserez pas réellement :
Lisp vaut la peine d'être appris pour l'expérience d'illumination profonde que vous aurez lorsque vous finirez par le comprendre ; cette expérience vous fera devenir un meilleur programmeur pour le reste de vos jours, même si vous n'utilisez jamais réellement Lisp lui-même beaucoup.
Si je ne connaissais pas Lisp, la lecture de ceci me ferait poser des questions. Un langage qui me ferait devenir un meilleur programmeur, si cela veut dire quelque chose, signifie un langage qui serait meilleur pour la programmation. Et c'est en fait l'implication de ce qu'Eric dit.
Tant que cette idée est encore en circulation, je pense que les hackers seront suffisamment réceptifs à un nouveau Lisp, même s'il s'appelle Lisp. Mais ce Lisp doit être un langage de hacker, comme les Lisps classiques des années 1970. Il doit être concis, simple et piratable. Et il doit avoir des bibliothèques puissantes pour faire ce que les hackers veulent faire maintenant.
En matière de bibliothèques, je pense qu'il y a de la place pour battre des langages comme Perl et Python à leur propre jeu. Beaucoup des nouvelles applications qui devront être écrites dans les années à venir seront des applications basées sur des serveurs. Il n'y a aucune raison pour qu'un nouveau Lisp n'ait pas des bibliothèques de chaînes aussi bonnes que Perl, et si ce nouveau Lisp avait aussi des bibliothèques puissantes pour les applications basées sur des serveurs, il pourrait être très populaire. Les vrais hackers ne bouderont pas un nouvel outil qui leur permettra de résoudre des problèmes difficiles avec quelques appels de bibliothèque. Rappelez-vous, les hackers sont paresseux.
Ce serait une victoire encore plus grande d'avoir un support de langage de base pour les applications basées sur des serveurs. Par exemple, un support explicite pour les programmes avec plusieurs utilisateurs, ou la propriété des données au niveau des balises de type.
Les applications basées sur des serveurs nous donnent également la réponse à la question de ce que ce nouveau Lisp sera utilisé pour pirater. Cela ne ferait pas de mal de rendre Lisp meilleur en tant que langage de script pour Unix. (Il serait difficile de le rendre pire.) Mais je pense qu'il y a des domaines où les langages existants seraient plus faciles à battre. Je pense qu'il serait peut-être préférable de suivre le modèle de Tcl, et de fournir le Lisp avec un système complet pour prendre en charge les applications basées sur des serveurs. Lisp est un ajustement naturel pour les applications basées sur des serveurs. Les fermetures lexicales offrent un moyen d'obtenir l'effet des sous-routines lorsque l'interface utilisateur n'est qu'une série de pages Web. Les S-expressions s'adaptent bien au HTML, et les macros sont bonnes pour le générer. Il faut de meilleurs outils pour écrire des applications basées sur des serveurs, et il faut un nouveau Lisp, et les deux fonctionneraient très bien ensemble.
12 Le langage de rêve
Pour résumer, essayons de décrire le langage de rêve du hacker. Le langage de rêve est beau, propre et concis. Il a un niveau supérieur interactif qui démarre rapidement. Vous pouvez écrire des programmes pour résoudre des problèmes courants avec très peu de code. Presque tout le code dans n'importe quel programme que vous écrivez est du code qui est spécifique à votre application. Tout le reste a été fait pour vous.
La syntaxe du langage est brève à défaut. Vous n'avez jamais à taper un caractère inutile, ni même à utiliser beaucoup la touche Maj.
En utilisant de grandes abstractions, vous pouvez écrire la première version d'un programme très rapidement. Plus tard, lorsque vous souhaitez optimiser, il existe un très bon profileur qui vous indique où concentrer votre attention. Vous pouvez rendre les boucles internes incroyablement rapides, même en écrivant du code d'octet en ligne si vous en avez besoin.
Il existe de nombreux bons exemples à apprendre, et le langage est suffisamment intuitif pour que vous puissiez apprendre à l'utiliser à partir d'exemples dans quelques minutes. Vous n'avez pas besoin de regarder beaucoup dans le manuel. Le manuel est mince et contient peu d'avertissements et de qualifications.
Le langage a un noyau petit et des bibliothèques puissantes et hautement orthogonales qui sont aussi soigneusement conçues que le langage de base. Les bibliothèques fonctionnent toutes bien ensemble ; tout dans le langage s'assemble comme les pièces d'un appareil photo de qualité. Rien n'est obsolète, ou conservé pour des raisons de compatibilité. Le code source de toutes les bibliothèques est facilement disponible. Il est facile de parler au système d'exploitation et aux applications écrites dans d'autres langages.
Le langage est construit en couches. Les abstractions de niveau supérieur sont construites de manière très transparente à partir d'abstractions de niveau inférieur, que vous pouvez obtenir si vous le souhaitez.
Rien ne vous est caché qui ne doit absolument pas l'être. Le langage n'offre des abstractions que comme un moyen de vous faire gagner du travail, plutôt que comme un moyen de vous dire quoi faire. En fait, le langage vous encourage à être un participant égal à sa conception. Vous pouvez changer tout ce qui le concerne, y compris sa syntaxe, et tout ce que vous écrivez a, autant que possible, le même statut que ce qui est pré-défini.
Notes
[1] Des macros très proches de l'idée moderne ont été proposées par Timothy Hart en 1964, deux ans après la sortie de Lisp 1.5. Ce qui manquait, initialement, c'était des moyens d'éviter la capture de variables et les évaluations multiples ; les exemples de Hart sont sujets aux deux.
[2] Dans When the Air Hits Your Brain, le neurochirurgien Frank Vertosick raconte une conversation dans laquelle son chef de résidence, Gary, parle de la différence entre les chirurgiens et les internistes ("puces") :
Gary et moi avons commandé une grande pizza et avons trouvé une cabine ouverte. Le chef a allumé une cigarette. "Regardez ces puces de merde, qui jacassent à propos d'une maladie qu'ils verront une fois dans leur vie. C'est le problème avec les puces, elles n'aiment que les trucs bizarres. Elles détestent leurs cas de pain et de beurre. C'est la différence entre nous et les puces de merde. Voyez, nous adorons les grosses hernies discales lombaires juteuses, mais elles détestent l'hypertension...."
Il est difficile de penser à une hernie discale lombaire comme étant juteuse (sauf littéralement). Et pourtant, je pense que je sais ce qu'ils veulent dire. J'ai souvent eu un bug juteux à traquer. Quelqu'un qui n'est pas un programmeur trouverait difficile d'imaginer qu'il puisse y avoir du plaisir dans un bug. C'est sûrement mieux si tout fonctionne simplement. D'une certaine manière, c'est le cas. Et pourtant, il y a indéniablement une satisfaction sombre à traquer certains types de bugs.