Être Populaire

Mai 2001

(Cet article a été écrit comme une sorte de plan d'affaires pour un nouveau langage. Il lui manque donc (car il la tient pour acquise) la caractéristique la plus importante d'un bon langage de programmation : des abstractions très puissantes.)

Un ami m'a un jour dit qu'il voulait concevoir un très bon langage de programmation à un éminent expert en systèmes d'exploitation. L'expert lui a répondu 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 que, 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 s'y prendrait-on ?

Je pense que les réponses à ces questions peuvent être trouvées en observant 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, certes, que la plupart des gens ne choisissent pas les langages de programmation uniquement en fonction de leurs mérites. La plupart des programmeurs se voient dicter le 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 grand qu'on le pense parfois. Je crois qu'un problème plus important est que l'idée qu'un hacker se fait d'un bon langage de programmation n'est pas la même que 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 humains, et ils doivent être conçus pour s'adapter aux forces et aux faiblesses humaines, tout comme les chaussures doivent être conçues pour les pieds humains. Si une chaussure pince quand vous la mettez, c'est une mauvaise chaussure, aussi élégante soit-elle en tant qu'œuvre sculpturale.

Il se peut que la majorité des programmeurs ne puissent pas distinguer un bon langage d'un mauvais. Mais il en va de même pour tout autre outil. Cela ne signifie pas que c'est une perte de temps d'essayer de concevoir un bon langage. Les hackers experts reconnaissent un bon langage quand ils en voient un, et ils l'utiliseront. Les hackers experts sont une minuscule minorité, certes, mais cette minuscule 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, d'ailleurs, ce n'est pas seulement de l'influence mais un commandement : souvent, les hackers experts sont les personnes mêmes 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 davantage les bons langages des mauvais, car les retours d'utilisateurs réels conduisent toujours à des améliorations. Regardez à quel point tout 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 des hackers du MIT aient passé quelques années à utiliser Lisp pour écrire de vrais programmes. [1]

Donc, qu'un langage doive être bon pour être populaire ou non, 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 avaient au MIT au milieu des années 1980, car 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 en entendront-ils parler ? Par d'autres hackers. Mais il doit y avoir un groupe initial de hackers utilisant le langage pour que d'autres en entendent parler. Je me demande quelle doit être la taille de ce groupe ; combien d'utilisateurs constituent une masse critique ? À vue de nez, je dirais vingt. Si un langage avait vingt utilisateurs distincts, c'est-à-dire vingt utilisateurs qui ont décidé d'eux-mêmes de l'utiliser, je le considérerais comme réel.

Y arriver ne doit pas être facile. Je ne serais pas surpris s'il é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 désirent, 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 plus tard, Perl aussi. 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 car ce n'est pas le langage de script d'un système massivement populaire. La popularité qu'il conserve remonte aux années 1960 et 1970, lorsqu'il était le langage de script du MIT. Beaucoup des grands programmeurs de l'époque ont été associés au MIT à un moment donné. Et au début des années 1970, avant C, le dialecte de 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 faite en Emacs Lisp ou AutoLisp.

Les langages de programmation n'existent pas isolément. Hacker est un verbe transitif — les hackers hackent généralement quelque chose — et en pratique, les langages sont jugés par rapport à ce qu'ils sont utilisés pour hacker. 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 que c'est un orphelin. Il était à l'origine livré avec un système à hacker : la Machine Lisp. Mais les Machines Lisp (ainsi que 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. Il est, hélas, 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. Une autre vue est qu'un langage de programmation n'est vraiment pas un langage de programmation à moins qu'il ne soit aussi le langage de script de quelque chose. Cela ne semble injuste que si cela vient comme une 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 juste 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 hackers individuels ne le feront pas, et ce sont les hackers que vous devez attirer.

Un langage a également besoin d'un livre à son sujet. Le livre doit être mince, bien écrit et plein de bons exemples. K&R est l'idéal ici. Pour l'instant, je dirais presque qu'un langage doit avoir un livre publié par O'Reilly. C'est en train de devenir le critère d'importance pour les hackers.

Il devrait également y avoir de la documentation en ligne. En fait, le livre peut commencer comme documentation en ligne. Mais je ne pense pas que les livres physiques soient déjà obsolètes. 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 de nouveaux langages.

3 Brièveté

Étant donné que vous pouvez fournir les trois choses dont tout langage a besoin — une implémentation gratuite, un livre et quelque chose à hacker — comment faire un langage que les hackers aimeront ?

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 précisément ainsi 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 choyer l'utilisateur avec des expressions verbeuses censées ressembler à l'anglais. Cobol est notoire pour ce défaut. Un hacker considérerait le fait d'être invité à é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 pendant les deux premières heures. Mais un hacker peut apprendre assez vite 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 ont également des longueurs différentes, ce qui signifie que les arguments ne s'aligneront pas lorsqu'ils sont appelés, comme car et cdr le sont souvent, sur des lignes successives. J'ai constaté que la façon dont le code s'aligne sur la page est très importante. Je peux à peine lire le code Lisp lorsqu'il est défini dans une police à largeur variable, et des amis disent que c'est également vrai pour d'autres langages.

La brièveté est un point où les langages fortement typés perdent. Toutes choses égales par ailleurs, personne ne veut commencer un programme par un tas de déclarations. Tout ce qui peut être implicite, devrait l'être.

Les jetons individuels devraient é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 nom long 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 occupe sur votre écran.

4 Hackabilité

Il y a une chose plus importante que la brièveté pour un hacker : pouvoir faire ce que l'on 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 inappropriées. C'est un plan dangereusement présomptueux. Comment le concepteur de langage peut-il savoir ce que le programmeur aura besoin de faire ? Je pense que les concepteurs de langages feraient mieux de considérer leur utilisateur cible comme un génie qui aura besoin de faire des choses qu'ils n'avaient jamais anticipées, plutôt qu'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 la référence à des variables dans un autre paquet, mais vous ne pouvez pas le sauver d'écrire un programme mal conçu pour résoudre le mauvais problème, et de prendre une éternité pour le faire.

Les bons programmeurs veulent souvent faire des choses dangereuses et peu ragoûtantes. Par peu ragoûtantes, j'entends des choses qui vont au-delà de 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 hacker, et hacker 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ères que vous n'aviez pas prévues, et c'est particulièrement vrai pour un outil très articulé comme un langage de programmation. Beaucoup de hackers voudront modifier votre modèle sémantique d'une manière que vous n'auriez jamais imaginée. Je dis, laissez-les faire ; donnez au programmeur accès à autant d'éléments 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 à travers les champs d'une structure — pour éliminer les références à un objet supprimé, par exemple, ou trouver des champs non 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, car c'est ce qu'une structure est censée signifier.

Un hacker ne voudra peut-être subvertir le modèle prévu des choses qu'une ou deux fois dans un grand programme. Mais quelle différence cela fait de pouvoir le faire. Et ce peut être plus qu'une question de simple résolution de problème. Il y a aussi une sorte de plaisir ici. Les hackers partagent le plaisir secret du chirurgien à fouiller dans des entrailles grossières, le plaisir secret de l'adolescent à percer 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 à leur guise. La correction politique de Common Lisp est une aberration. Les premiers Lisps vous laissaient mettre la main sur tout. Une bonne partie de cet esprit est, heureusement, préservée dans les macros. Quelle chose merveilleuse, de pouvoir effectuer 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 retourne 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 comprendre ce qu'elles font. Je n'ai jamais entendu les macros hygiéniques expliquées en une seule 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 destiné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 à leur guise. C est comme ça. Les premiers Lisps l'étaient aussi. Un vrai langage de hacker aura toujours un caractère légèrement canaille.

Un bon langage de programmation devrait avoir des fonctionnalités qui feraient secouer la tête avec désapprobation aux personnes qui utilisent l'expression « ingénierie logicielle ». À l'autre extrémité du continuum se trouvent des langages comme Ada et Pascal, des modèles de bienséance 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 étonnamment, 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. La chose surprenante à propos des programmes jetables 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 en de vrais programmes, avec de vraies fonctionnalités et de vrais utilisateurs.

J'ai l'impression 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. Quand les gens entreprennent un projet trop grand, ils sont submergés. Le projet s'enlise, ou le résultat est stérile et rigide : 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, on découvrirait que c'est ainsi que la plupart des grands programmes ont été développés. Et ceux qui ont évolué de cette façon sont probablement toujours é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 créer un langage utilisé pour de 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 lui-même à peu près un programme jetable. Perl a commencé sa vie comme une collection d'utilitaires pour générer des rapports, et n'a évolué en un langage de programmation que lorsque les programmes jetables que les gens y écrivaient sont devenus plus grands. Ce n'est qu'avec Perl 5 (si tant est que ce soit le cas) 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 déjà être installé sur l'ordinateur que vous utilisez. Ce 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 devrait être interactif et démarrer rapidement.

Une autre chose que vous voulez dans un programme jetable est la brièveté. La brièveté est toujours attrayante pour les hackers, et jamais autant que dans un programme qu'ils s'attendent à produire en une heure.

6 Bibliothèques

Bien sûr, le summum de la brièveté est d'avoir le programme déjà écrit pour vous, et de simplement l'appeler. Et cela nous amène à ce qui, je pense, sera 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 grandes bibliothèques pour manipuler des chaînes de caractères. Cette classe de fonctions de bibliothèque est particulièrement importante pour les programmes jetables, qui sont souvent initialement écrits pour convertir ou extraire des données. De nombreux programmes Perl commencent probablement par juste quelques appels de bibliothèque assemblés.

Je pense que beaucoup des avancées 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 futurs langages de programmation 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 autre, mais sur la façon de concevoir de grandes bibliothèques. Le genre de concepteurs de langages qui aiment réfléchir à la conception des systèmes de types pourrait frissonner à cette idée. C'est presque comme écrire des applications ! Tant pis. 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. Il ne s'agit pas simplement d'écrire beaucoup de code. Une fois que les bibliothèques deviennent trop grandes, il peut parfois prendre plus de temps de trouver la fonction dont vous avez besoin que d'é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 point où Common Lisp est en deçà. Il n'y a que des bibliothèques rudimentaires pour manipuler des chaînes de caractères, et presque aucune pour communiquer avec le système d'exploitation. Pour des raisons historiques, Common Lisp essaie de prétendre que l'OS n'existe pas. Et parce que vous ne pouvez pas communiquer avec l'OS, 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 ont tendance à ne pas vous donner tout ce que vous voulez. Les hackers auraient une bien meilleure opinion de Lisp si Common Lisp avait de puissantes bibliothèques de chaînes et un bon support OS.

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 de pires problèmes qu'une syntaxe peu familière. Je connais plusieurs programmeurs qui sont à l'aise avec la syntaxe préfixée et pourtant utilisent Perl par défaut, car il possède de puissantes bibliothèques de chaînes et peut communiquer avec l'OS.

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 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 les opinions des programmeurs ordinaires comptent. Les langages deviennent populaires ou impopulaires en fonction de ce que les hackers experts en pensent, et je pense que les hackers experts pourraient être capables 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. Au contraire, cela a peut-être contribué à favoriser un culte Perl.

Un problème plus sérieux est la diffusité de la notation préfixée. Pour les hackers experts, c'est vraiment un problème. Personne ne veut écrire (aref a x y) quand ils pourraient écrire a[x,y].

Dans ce cas particulier, il y a un moyen de nous sortir du problème avec finesse. Si nous traitons les structures de données comme si elles étaient des 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 nous débarrasser (ou rendre facultatives) de beaucoup de parenthèses en rendant l'indentation significative. C'est ainsi que les programmeurs lisent le code de toute façon : quand l'indentation dit une chose et les délimiteurs en disent une autre, nous nous basons sur l'indentation. Traiter l'indentation comme significative éliminerait cette source courante de bugs tout en raccourcissant les programmes.

Parfois, la syntaxe infixée est plus facile à lire. C'est particulièrement vrai pour les expressions mathématiques. J'ai utilisé Lisp toute ma vie de programmeur et je ne trouve toujours pas les expressions mathématiques préfixées naturelles. Et pourtant, il 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 être religieusement opposés à l'introduction de syntaxe dans Lisp, tant qu'elle se traduit de manière bien comprise en s-expressions sous-jacentes. Il y a déjà une bonne dose de syntaxe dans Lisp. Ce n'est pas nécessairement mauvais d'en introduire davantage, tant que personne n'est forcé de l'utiliser. En Common Lisp, certains délimiteurs sont réservés au langage, suggérant qu'au moins certains des concepteurs avaient l'intention d'avoir plus de syntaxe à l'avenir.

L'une des pièces de syntaxe les plus manifestement non-Lisp de Common Lisp se trouve dans les chaînes de format ; 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 y être inclus. 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'ouvrait à la section format. Le mien aussi. Cela indique probablement une marge d'amélioration. Cela peut aussi signifier que les programmes font beaucoup d'E/S.

8 Efficacité

Un bon langage, comme chacun sait, devrait générer du code rapide. Mais en pratique, je ne pense pas que le code rapide provienne principalement de ce que vous faites dans la conception du langage. Comme Knuth l'a souligné 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, disons, 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 avez besoin de pouvoir déclarer les types d'arguments dans les goulots d'étranglement. Et encore plus, vous avez besoin de pouvoir découvrir 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 en tout cas, je pense qu'un bon profilage contribuerait grandement à résoudre le problème : vous apprendriez vite ce qui est coûteux.

Une partie du problème ici est sociale. Les concepteurs de langages aiment écrire des compilateurs rapides. C'est ainsi qu'ils mesurent leurs compétences. Ils considèrent le profileur comme un add-on, 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 déconnectés de leurs utilisateurs. Ils font un très bon travail pour résoudre un problème légèrement erroné.

Il pourrait être une bonne idée d'avoir un profileur actif — de pousser les données de performance au 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 édite 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 avantage particulièrement important dans les applications basées sur serveur, 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 indicateur de problèmes. Dans un endroit où je travaillais, 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 faisaient 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, au 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 modèles d'accès à la mémoire s'avéraient être des signes certains de mauvais algorithmes. S'il y avait un petit bonhomme courant à l'intérieur de l'ordinateur 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 dans de nombreuses chasses à l'oie sauvage, mais je n'ai jamais eu de bonne façon de voir 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 faciliter le portage de l'implémentation, mais cela pourrait être une caractéristique de langage utile. Il pourrait être une bonne idée de faire du bytecode une partie officielle du langage, et de permettre aux programmeurs d'utiliser le bytecode en ligne dans les goulots d'étranglement. Alors de telles optimisations seraient également portables.

La nature de la vitesse, telle que perçue par l'utilisateur final, pourrait changer. Avec la montée des applications basées sur serveur, de plus en plus de programmes pourraient s'avérer être 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 supporter par processeur. Beaucoup des applications intéressantes écrites dans un avenir proche seront des applications basées sur serveur, et le nombre d'utilisateurs par serveur est la question critique pour quiconque héberge de telles applications. Dans le coût en capital d'une entreprise offrant une application basée sur serveur, c'est le diviseur.

Pendant des années, l'efficacité n'a pas beaucoup compté dans la plupart des applications utilisateur final. 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, le logiciel s'est étendu pour utiliser les ressources disponibles. Cela changera avec les applications basées sur serveur. Dans ce monde, le matériel et le logiciel seront fournis ensemble. Pour les entreprises qui proposent des applications basées sur serveur, le nombre d'utilisateurs qu'elles peuvent supporter par serveur fera une très grande différence sur le résultat net.

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 aider ici aussi. 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 Le 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 tant de langages de programmation. La plupart des hackers auront donc 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 ami à moi fait rarement quelque chose la première fois qu'on lui demande. Il sait que les gens demandent parfois des choses qu'ils ne veulent finalement pas. Pour éviter de perdre son temps, il attend la troisième ou quatrième fois qu'on lui demande de faire quelque chose ; à ce moment-là, celui qui lui demande peut être assez agacé, mais au moins il veut probablement vraiment ce qu'il demande.

La plupart des gens ont appris à faire un filtrage similaire sur les nouveautés 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 à la mode s'avèrent être une perte de temps, et finissent par disparaître. En retardant l'apprentissage de VRML, j'ai évité d'avoir à l'apprendre du tout.

Donc, quiconque 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 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 juste déconnectés.

La bonne nouvelle 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 finalement les gens commenceront à écouter. 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à.

Il est tout aussi bien que cela prenne généralement un certain temps pour prendre de l'élan. La plupart des technologies évoluent beaucoup même après leur lancement initial — les langages de programmation en particulier. Rien ne pourrait être mieux, pour une nouvelle technologie, que quelques années d'utilisation par un petit nombre de premiers adoptants seulement. Les premiers adoptants sont sophistiqués et exigeants, et débusquent rapidement les défauts restants dans votre technologie. Lorsque vous n'avez que quelques utilisateurs, vous pouvez être en contact étroit avec chacun d'eux. Et les premiers adoptants sont indulgents lorsque vous améliorez votre système, même si cela cause des ruptures.

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 exemplifiée par la startup de garage classique, sous-financée et improvisée. Quelques 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 d'améliorer la technologie, et pendant ce temps, leur base d'utilisateurs grandit par le bouche-à-oreille. Avant de s'en rendre compte, ils sont grands.

L'autre approche, la méthode du big bang, est exemplifiée par la startup financée par des VC et fortement commercialisée. Ils se précipitent pour développer un produit, le lancent avec une grande publicité, et immédiatement (ils l'espèrent) ont 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 VC. Ils peuvent se permettre le meilleur de tout, et la campagne de relations publiques entourant le lancement a pour effet secondaire d'en faire 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 se trompent souvent de se plaindre. 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 aujourd'hui, vous constaterez que la plupart d'entre elles ont grandi organiquement.

Ce modèle ne s'applique pas seulement aux entreprises. On le voit aussi dans la recherche sponsorisée. Multics et Common Lisp étaient des projets big-bang, et Unix et MacLisp étaient des projets de croissance organique.

10 Refonte

« La meilleure écriture est la réécriture », a écrit E. B. White. Tout bon écrivain le sait, et c'est vrai aussi pour les logiciels. La partie la plus importante de la conception est la refonte. Les langages de programmation, en particulier, ne sont pas suffisamment refondus.

Pour écrire de bons logiciels, vous devez simultanément garder deux idées opposées en 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-il être difficile ? avec une moitié de votre cerveau tout en pensant cela ne marchera jamais avec l'autre.

L'astuce est de réaliser qu'il n'y a pas de réelle 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 jusqu'à présent.

Les personnes qui font du bon travail pensent souvent que ce sur quoi elles travaillent n'est pas bon. D'autres voient ce qu'elles ont fait et sont pleins d'émerveillement, mais le créateur est plein d'inquiétude. 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 pourrez le résoudre. Dans la deuxième phase, vous regardez ce que vous avez fait à la lumière froide du matin, et voyez très clairement tous ses défauts. Mais tant que votre esprit critique ne l'emporte pas sur votre espoir, vous pourrez regarder votre système certes incomplet, et penser, à quel point cela peut-il être difficile d'aller jusqu'au bout ?, poursuivant ainsi le cycle.

Il est difficile 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'oseront même pas entreprendre des projets ambitieux.

Tout ce que vous pouvez faire pour maintenir le cycle de refonte en marche 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 suffisamment refondus. La prose a des lecteurs, mais les logiciels ont des utilisateurs. Si un écrivain réécrit un essai, les personnes qui ont lu l'ancienne 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. Alors choisissez vos utilisateurs avec soin, et soyez lent à augmenter leur nombre. Avoir des utilisateurs, c'est comme l'optimisation : la sage décision 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 retirer un pansement : la douleur est un souvenir presque dès que vous la ressentez.

Tout le monde sait que ce n'est pas une bonne idée de faire concevoir un langage par un comité. Les comités produisent de mauvais designs. Mais je pense que le pire danger des comités est qu'ils interfèrent avec la refonte. C'est tellement de travail d'introduire des changements que personne ne veut s'en donner la peine. 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 entrave la refonte. Cela se produit particulièrement dans les interfaces entre des morceaux de logiciel écrits par deux personnes différentes. Pour changer l'interface, les deux doivent accepter de la changer 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. Alors l'interface aura tendance à être possédée par l'un d'eux. Le niveau inférieur des deux sera soit un langage dans lequel le supérieur est écrit, auquel cas le niveau inférieur possédera 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 nous a peut-être 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 à hacker. Common Lisp n'a ni l'un ni l'autre. Un langage de hacker est concis et hackable. 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 vrai 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 emprunté de plus en plus de fonctionnalités à 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 édulcoré avec une syntaxe infixée et sans macros. Un nouveau Lisp serait une étape naturelle dans cette progression.

Je pense parfois que ce serait une bonne astuce marketing de l'appeler une version améliorée de Python. Cela sonne 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 en L. Mais je suppose que nous ne devrions pas avoir peur d'appeler le nouveau Lisp, Lisp. Lisp a encore beaucoup de respect latent parmi les meilleurs hackers — ceux qui ont suivi le 6.001 et l'ont compris, par exemple. Et ce sont les utilisateurs que vous devez gagner.

Dans « How to Become a Hacker », Eric Raymond décrit Lisp comme quelque chose de similaire au latin ou au 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 le comprendrez enfin ; cette expérience fera de vous un meilleur programmeur pour le reste de vos jours, même si vous n'utilisez jamais beaucoup Lisp lui-même.

Si je ne connaissais pas Lisp, lire cela me ferait poser des questions. Un langage qui ferait de moi un meilleur programmeur, si cela signifie quoi que ce soit, 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 est appelé Lisp. Mais ce Lisp doit être un langage de hacker, comme les Lisps classiques des années 1970. Il doit être concis, simple et hackable. 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 serveur. 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 également de puissantes bibliothèques pour les applications basées sur serveur, il pourrait être très populaire. Les vrais hackers ne dédaigneront 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 pourrait être un avantage encore plus grand d'avoir un support du langage de base pour les applications basées sur serveur. Par exemple, un support explicite pour les programmes multi-utilisateurs, ou la propriété des données au niveau des étiquettes de type.

Les applications basées sur serveur nous donnent également la réponse à la question de savoir à quoi servira ce nouveau Lisp. Il 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 préférable de suivre le modèle de Tcl, et de fournir le Lisp avec un système complet pour supporter les applications basées sur serveur. Lisp est adapté naturellement aux applications basées sur serveur. Les fermetures lexicales offrent un moyen d'obtenir l'effet de sous-routines lorsque l'interface utilisateur n'est qu'une série de pages web. Les S-expressions se mappent bien sur le HTML, et les macros sont bonnes pour le générer. Il doit y avoir de meilleurs outils pour écrire des applications basées sur serveur, et il doit y avoir un nouveau Lisp, et les deux fonctionneraient très bien ensemble.

12 Le Langage de Rêve

En guise de résumé, essayons de décrire le langage de rêve du hacker. Le langage de rêve est beau, propre et concis. Il a un toplevel 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 de tout programme que vous écrivez est du code spécifique à votre application. Tout le reste a été fait pour vous.

La syntaxe du langage est brève à l'excès. 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 voulez optimiser, il y a un très bon profileur qui vous dit où concentrer votre attention. Vous pouvez rendre les boucles internes incroyablement rapides, même en écrivant du bytecode en ligne si vous en avez besoin.

Il y a beaucoup de bons exemples à apprendre, et le langage est suffisamment intuitif pour que vous puissiez apprendre à l'utiliser à partir d'exemples en quelques minutes. Vous n'avez pas besoin de consulter beaucoup le manuel. Le manuel est mince, et contient peu d'avertissements et de qualifications.

Le langage a un petit noyau, et des bibliothèques puissantes, hautement orthogonales, 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 déprécié, ni conservé pour la compatibilité. Le code source de toutes les bibliothèques est facilement disponible. Il est facile de communiquer avec le système d'exploitation et avec les applications écrites dans d'autres langages.

Le langage est construit en couches. Les abstractions de plus haut niveau sont construites de manière très transparente à partir d'abstractions de plus bas niveau, dont vous pouvez vous emparer si vous le souhaitez.

Rien ne vous est caché qui ne doive absolument l'être. Le langage n'offre des abstractions que pour vous épargner du travail, plutôt que pour vous dire quoi faire. En fait, le langage vous encourage à être un participant égal à sa conception. Vous pouvez tout changer, 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 furent 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 l'évaluation multiple ; les exemples de Hart y sont sujets.

[2] Dans When the Air Hits Your Brain, le neurochirurgien Frank Vertosick raconte une conversation dans laquelle son chef de clinique, Gary, parle de la différence entre les chirurgiens et les internistes (« puces ») :

Gary et moi avons commandé une grande pizza et trouvé une cabine libre. Le chef a allumé une cigarette. « Regarde ces putains de puces, jacassant sur une maladie qu'elles ne verront qu'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 courants. C'est la différence entre nous et ces putains de puces. Tu vois, nous aimons les grosses hernies discales lombaires juteuses, mais elles détestent l'hypertension.... »

Il est difficile de considérer une hernie discale lombaire comme juteuse (sauf littéralement). Et pourtant, je crois savoir ce qu'ils veulent dire. J'ai souvent eu un bug juteux à traquer. Quelqu'un qui n'est pas programmeur aurait du mal à imaginer qu'il puisse y avoir du plaisir dans un bug. Sûrement, c'est mieux si tout fonctionne. D'une certaine manière, oui. Et pourtant, il y a indéniablement une satisfaction sombre à traquer certains types de bugs.