2 points par GN⁺ 2024-06-03 | 1 commentaires | Partager sur WhatsApp
  • La Spring Lisp Game Jam 2024 a reçu 48 jeux, un nouveau record, et les participations se divisent nettement entre l’approche qui ajoute Lisp par-dessus et celle qui construit toute la stack elle-même en Lisp
  • L’approche glaçage consiste à ajouter Lisp comme couche de scripting au-dessus d’un programme basé sur C/Rust/Lua pour obtenir rapidement des résultats, mais elle reste fortement liée au langage statique sous-jacent et à sa toolchain
  • L’approche gâteau consiste à écrire l’essentiel du programme en Lisp et à minimiser la FFI C pour obtenir un contrôle plus profond, mais le coût devient plus élevé pour l’implémentation de bibliothèques, l’écriture de wrappers et le déploiement web
  • Dans la Game Jam, Fennel+love2d et S7+raylib relèvent davantage du glaçage, Guile+Chickadee du gâteau, tandis que Hoot+HTML5 canvas se rapproche aussi du gâteau grâce à sa toolchain Wasm basée sur Scheme
  • Plus la part de Lisp augmente, plus on gagne en live hacking, en sûreté mémoire, en réduction de la frontière Lisp/C et en hackabilité ; des projets comme Guix, Trial et Pre-Scheme vont dans la même direction

État des soumissions de la Spring Lisp Game Jam 2024

  • La Spring Lisp Game Jam 2024 s’est terminée il y a une semaine, avec 48 jeux soumis, ce qui établit un nouveau record pour la jam
  • Les participants ont ensuite passé une semaine à jouer aux jeux des autres et à les évaluer
  • La répartition des soumissions par langage est la suivante
    • Guile : 15, 31 %
    • Fennel : 10, 21 %
    • Clojure : 5, 10 %
    • Common Lisp : 5, 10 %
    • Racket : 4, 8 %
    • Elisp : 4, 8 %
    • S7 : 3, 6 %
    • Kawa : 1, 2 %
    • Owl : 1, 2 %
  • Part de Guile : {p:31}
  • Les implémentations Scheme n’ont pas été regroupées dans une seule catégorie scheme, car la spécification de Scheme est réduite, et Guile, Racket, S7 et Kawa sont des implémentations aux objectifs différents
  • Dans cette jam, Guile enregistre pour la première fois le plus grand nombre de soumissions
    • Parmi les 15 jeux Guile, 11 sont des jeux web réalisés avec Hoot
    • Hoot est un compilateur Scheme-vers-WebAssembly en cours de développement au Spritely Institute
    • 2 de ces 11 jeux sont des projets officiels de Spritely
    • Le Spritely Institute avait demandé, avant le début de la jam, d’essayer de créer des jeux avec Hoot, et beaucoup de participants ont répondu à l’appel
  • Habituellement, le langage le plus populaire de cette jam est Fennel, un Lisp qui compile en Lua
  • Les 3 jeux utilisant S7 constituent eux aussi des exemples liés à la manière d’utiliser Lisp dans le développement de jeux

Utiliser Lisp comme glaçage

  • Le modèle glaçage consiste à poser Lisp comme langage de scripting au-dessus d’un « gâteau » écrit dans un langage statique comme C ou Rust
  • En général, cela implique d’intégrer un interpréteur Lisp dans un programme plus vaste
  • Si l’on veut écrire en Lisp les parties de haut niveau d’une application, c’est souvent la voie la plus rapide
    • Il faut disposer d’un interpréteur ou compilateur adapté
    • Il faut aussi un moyen d’ajouter les hooks nécessaires à l’application
  • Si la partie principale du programme est écrite en C ou en Rust, on peut la compiler en WebAssembly avec emscripten pour la déployer sur le web
  • On peut obtenir rapidement des résultats satisfaisants, mais au prix d’un fort couplage avec le langage statique et sa toolchain
  • Exemples représentatifs
    • S7 est un Scheme embarquable
    • Guile peut aussi servir à étendre des programmes C, mais au lieu d’inclure un interpréteur dans l’exécutable, on le lie généralement dynamiquement à libguile
    • Fennel exploite des applications existantes disposant de points d’extension Lua, en compilant un langage de type Lisp vers Lua

Utiliser Lisp comme gâteau

  • Le modèle gâteau consiste à implémenter autant que possible la stack logicielle en Lisp
  • Au lieu d’insérer Lisp dans un programme non-Lisp, on écrit la majeure partie du programme en Lisp
  • Si nécessaire, on appelle des bibliothèques partagées via une interface de fonctions étrangères (FFI), mais mieux vaut en limiter l’usage
  • Il faut plus de temps avant d’obtenir des résultats
    • Il faut implémenter soi-même les bibliothèques absentes de l’implémentation Lisp choisie
    • Il faut écrire des wrappers pour les bibliothèques partagées C incontournables
    • Le projet ne devient pas facilement une cible emscripten, ce qui complique le déploiement web
  • Cette approche rejoint le débat classique embed vs. extend
  • Guile peut servir pour le glaçage, mais il montre davantage ses forces dans une approche gâteau
    • La vision initiale de Guile était de transformer d’autres programmes en quelque chose de comparable à Emacs en leur ajoutant un interpréteur Scheme
    • Aujourd’hui, la bonne pratique consiste à écrire le programme en Scheme dès le départ
  • Common Lisp est également un bon exemple de l’approche gâteau
    • Des implémentations comme SBCL offrent une bonne FFI C
    • Elles peuvent compiler vers des exécutables natifs efficaces, ce qui réduit les cas où l’on aurait envie d’utiliser C pour des raisons de performance

Glaçage et gâteau à travers les cas de la Game Jam

  • Fennel + love2d

    • love2d est depuis longtemps un choix populaire pour le développement de jeux en solo ou en petite équipe
    • love2d est un programme C++ avec un interpréteur Lua intégré, ce qui en fait une bonne cible pour Fennel
    • La plupart des distributions Linux empaquettent love2d, ce qui facilite l’exécution native des fichiers .love
    • Grâce à emscripten, les jeux love2d peuvent aussi être déployés sur le web
    • C’est pourquoi la plupart des jeux Fennel utilisent love2d
    • ./soko.bin et Gnomic Vengeance utilisent cette stack
    • Fennel+love2d est un exemple parfait de Lisp as icing
    • Fennel se trouve tout en haut de la stack, et il n’existe pratiquement aucun moyen de diffuser Lisp vers les couches inférieures
    • C’est à ce jour la stack de développement de jeux en Lisp la plus réussie
  • S7 + raylib

    • Dans cette jam, deux jeux, GhostHop et Life Predictor, utilisent la stack S7+raylib
    • Raylib est une bibliothèque C disposant de bindings dans plusieurs langages de haut niveau, et sa popularité a fortement progressé ces dernières années
    • S7 est lui aussi implémenté en C et s’embarque facilement, ce qui rend cette combinaison facile à déployer sur le web via emscripten
    • S7+raylib est également un exemple de Lisp as icing, et il sera intéressant de voir si cette stack gagnera en popularité dans les prochaines jams
  • Guile + Chickadee

    • Chickadee est une bibliothèque de jeu pour Guile, qui implémente en Scheme presque toutes les parties intéressantes, y compris le rendu
    • Lors des jams récentes, deux jeux ont été réalisés avec Chickadee : Turbo Racer 3000 et Bloatrunner
    • Guile+Chickadee est un exemple de Lisp as cake
    • Chickadee encapsule certaines bibliothèques C pour les tâches bas niveau comme le chargement d’images, d’audio ou de polices, mais son propre code est écrit en Scheme pur
    • Les calculs matriciels et vectoriels sont eux aussi entièrement implémentés en Scheme
    • La bibliothèque fournit un ensemble de primitives de rendu comparable à celui de love2d et raylib, là encore implémenté en Scheme
    • Alors que d’autres bibliothèques de jeu Lisp s’appuient souvent sur des bibliothèques C comme nanosvg, Chickadee progresse aussi sur un rendu vectoriel implémenté en Scheme
    • Chickadee a poussé dans ses retranchements le compilateur et la machine virtuelle de Guile, et Guile s’est amélioré au passage
    • Cela dit, comme le projet a surtout été développé par une seule personne sur son temps libre limité, atteindre la parité fonctionnelle avec des bibliothèques de développement de jeux plus populaires prend beaucoup de temps
    • Même dans son état actuel, cela fonctionne déjà plutôt bien pour cet usage
  • Hoot + HTML5 canvas

    • Hoot est un compilateur Scheme-vers-WebAssembly
    • Hoot ne compile pas la VM Guile écrite en C vers du Wasm via emscripten
    • À la place, il implémente une toolchain Wasm complète et un nouveau backend pour le compilateur Guile, capable d’émettre directement du Wasm
    • Hoot est entièrement écrit en Scheme
    • Alors qu’un programme C compilé avec emscripten cible Wasm 1.0, fondé sur une mémoire linéaire, Hoot cible Wasm 2.0 avec des types de tas gérés par GC
    • Grâce à cette architecture, les binaires Hoot n’embarquent pas de garbage collector pour la distribution
    • Ils sont donc bien plus petits qu’un runtime Lisp compilé avec emscripten
    • Le binaire Wasm d’un jeu Hoot fait moins de 2 MiB, alors que le love.wasm d’un jeu love2d vérifié approchait les 6 MiB
    • Les programmes Hoot interopèrent facilement avec JavaScript
      • Les objets Scheme peuvent facilement être passés à JavaScript
      • Les objets JavaScript peuvent aussi être passés à Scheme
      • Les objets des deux côtés sont gérés sur le même tas
    • Les API du navigateur sont accessibles via des imports Wasm, ce qui fait de l’API HTML5 canvas intégrée un choix simple pour le rendu 2D dans les jeux
    • Cette jam comptait 11 jeux utilisant Hoot, dont Cirkoban et Lambda Dungeon
    • Hoot+HTML5 canvas correspond à un gâteau assez épais, avec un peu de glaçage par-dessus
    • Le bootstrapping de Hoot a demandé un an et un financement important
    • Au lieu d’utiliser emscripten, le projet a créé sa propre toolchain et étendu le compilateur Guile
    • Il existe aussi un interpréteur Wasm fonctionnant sur la VM Guile
    • En revanche, l’API canvas reste très haut niveau
    • Une approche encore plus proche du gâteau consisterait à appeler WebGL ou WebGPU via la FFI JS de Hoot
    • Les plans futurs visent WebGL/WebGPU, ce qui nécessitera des améliorations de Wasm GC
    • Un autre objectif est de porter Chickadee sur Hoot afin de rendre les jeux Chickadee aussi faciles à jouer en natif et dans le navigateur que les jeux love2d

Limites et avantages de l’approche gâteau

  • L’approche gâteau a elle aussi des limites évidentes
  • L’environnement moderne n’est pas celui des machines Lisp, et même le plus haut gâteau Lisp repose pour l’essentiel sur un gâteau plus grand encore, écrit en C
  • Les systèmes Lisp modernes finissent toujours par atteindre des couches inférieures
    • Emacs repose sur un cœur en C
    • La VM Guile est écrite en C
    • Hoot s’exécute au-dessus de gros moteurs JavaScript en C++ comme V8
    • Les jeux Hoot se rendent aujourd’hui via HTML5 canvas, et non via WebGL/WebGPU
    • L’usage d’OpenGL nécessite libGL
    • Chickadee utilise guile-opengl, qui appelle libGL via la FFI C
    • libpng, FreeType et d’autres bibliothèques existent aussi
  • Réécrire l’intégralité de tout cela en Lisp poserait un énorme problème de ressources
  • Malgré tout, récupérer une partie de la stack depuis des langages comme C reste une petite victoire
  • Les parties écrites en Lisp sont plus faciles à hacker, et certaines permettent même le live hacking pendant l’exécution du programme
  • Un runtime géré par GC apporte en général une meilleure sûreté mémoire
  • Réduire les appels FFI diminue le coût du passage de la frontière Lisp/C et améliore aussi la sécurité
  • Plus la part de Lisp augmente dans la stack, plus on se rapproche du gâteau que du glaçage

Exemples de gâteau hors du jeu vidéo

  • Guix est un bon exemple de la puissance que peut atteindre l’approche gâteau
  • Guix reprend le modèle de packaging fonctionnel du projet Nix en le réimplémentant, tout en remplaçant le langage Nix par Guile
  • Les raisons sont le code staging, le partage de code et une meilleure hackabilité
  • Guix utilise aussi, à la place de systemd, un système d’init écrit en Guile, pour les mêmes raisons
  • À ses débuts, Guix s’exposait facilement à la critique consistant à dire qu’il réinventait la roue sans raison, mais dix ans plus tard, cette insistance à maximiser l’usage de Lisp s’est révélée essentielle au succès du projet
  • En apprenant les idiomes de Guix et un peu de Guile, les utilisateurs acquièrent un puissant moyen de configurer leur système d’exploitation exactement comme ils le souhaitent
  • On peut voir Guix comme l’expérience la plus proche d’une machine Lisp sur du matériel moderne
  • Côté Common Lisp, le moteur de jeu Trial illustre lui aussi une approche où une grande partie est implémentée en Common Lisp plutôt que de simplement encapsuler des bibliothèques C
  • Des projets comme Pre-Scheme laissent espérer qu’un jour même les couches sous le runtime géré par GC pourront être implémentées en Lisp
    • Pre-Scheme est développé et utilisé avec succès dans Scheme 48
    • Un renouveau moderne est attendu grâce à une subvention NLnet

Vers des stacks davantage construites en Lisp

  • La direction va plutôt du côté du gâteau
  • Il faut davantage de projets qui continuent à repousser les frontières de ce que Lisp peut faire
  • Dans la Lisp Game Jam, le plus intéressant n’est pas tant les jeux eux-mêmes que ces petits progrès consistant à récupérer un morceau de gâteau à ce vieux C sec et poussiéreux
  • Dans le développement de jeux avec Guile, l’objectif est de continuer à repousser les limites avec le projet Chickadee
  • La conclusion n’est pas de tout réécrire en Rust, mais de tout réécrire en Lisp

1 commentaires

 
GN⁺ 2024-06-03
Réactions sur Hacker News
  • Ça faisait plaisir à lire, car on voit rarement ce genre d’article qui compare objectivement des approches logicielles
    Même quand on essaie d’en trouver, les résultats de recherche ont souvent du mal à dépasser le spam SEO de nos jours
    Janet semble avoir été conçu pour le jeu, et il a l’air d’inclure étonnamment beaucoup de choses « batteries included » comme des serveurs web ou des fonctions graphiques, donc j’ai été un peu surpris de ne voir aucun jeu utilisant Janet
    Côté Lisp et jeu vidéo, ça me semble être un langage qui vaut le détour

  • Content de voir s7 attirer l’attention
    Je l’ai utilisé en Scheme pour Max, une extension open source qui intègre un interpréteur Scheme dans l’environnement de musique assistée par ordinateur Max/MSP, et il se situe quelque part entre Guile, Clojure et Common Lisp tout en restant très petit et facile à embarquer
    Le fait qu’il soit sous licence BSD, bien plus permissive que Guile, est aussi un bon point
    Si vous aimez les macros de Common Lisp avec environnements de première classe, il y a de bonnes chances que s7 vous plaise aussi
    Il était aussi très facile à utiliser avec WASM, et c’est ainsi que je m’en sers dans un projet d’éducation musicale
    Il n’a pas non plus été difficile de créer une fonction générique permettant d’appeler des fonctions JS depuis Scheme et inversement, ce qui a rendu l’ensemble très fluide

    • Une voix de plus pour s7
      Nous avons réussi à embarquer s7 et SQLite comme moteur hors graphismes dans des apps natives iOS et Android
      C’était très rapide, le FFI était bon, c’était stable et léger, et nous avons beaucoup profité du code partagé entre apps mobiles, de tests unitaires extrêmement rapides et d’un outillage propre
      Au final, nous sommes passés à Fennel, un Lisp plus pratique sur mobile
      Nous étions presque les seuls à utiliser s7 sur mobile, alors que Lua était bien plus courant comme langage d’extension mobile, et l’état de compatibilité r7rs Scheme a aussi pesé dans la balance
      Comme nous utilisions Guile pour le développement desktop et s7 pour la distribution, nous étions souvent freinés par de petites incompatibilités, par exemple l’ordre d’évaluation des arguments
      s7 comme Fennel ont d’excellents projets et communautés
  • Je recommande particulièrement de regarder de près le Spritely Institute, jusqu’à son blog
    Je ne veux pas gâcher la découverte de ce qu’ils font, mais c’est un sujet et une organisation qui méritent qu’on creuse
    J’ai passé plus de 10 heures rien qu’à lire le blog, les liens associés et les projets
    https://spritely.institute/archive/

    • On dirait qu’ils attirent de bonnes personnes et font des choses assez formidables
  • Le résumé « nous ne vivons pas dans le monde des machines Lisp, mais dans un monde de PDP-11 glorifiés » m’a marqué
    Cela dit, je me demande s’il existe aussi du « glaçage » qui fonctionne avec sdl

    • Il est difficile de qualifier les CPU traditionnels de PDP-11 glorifiés
      Ils sont comparables en tant que machines de von Neumann à mémoire non taguée, mais les CPU classiques ont commencé à dépasser les machines Lisp vers le milieu des années 1980, quand les microprocesseurs 32 bits sont devenus courants et que les technologies de compilation Lisp ont évolué en conséquence
      Et même l’aspect « mémoire non taguée » pourrait ne pas rester vrai si l’on regarde des évolutions comme CHERI, ce qui laisse une vraie possibilité de retour en force des architectures de style LispM
    • J’adorais vraiment le PDP-11
      J’ai gardé un PDP-11/45 dans mon salon pendant quelques années, puis je l’ai remplacé plus tard par quelques H-11 LSI-11/2 avec deux lecteurs de disquettes 8 pouces pour gagner de la place
      Le PDP-11 n’est pas seulement une sorte de matrice d’Unix, il était aussi conceptuellement bien conçu
      Tout comme nous préférons des routines qui « tiennent sur un écran », le petit espace d’adressage direct du PDP-11 poussait vers des modules pas trop gros et encourageait la modularité
      Est-ce insuffisant aujourd’hui ? Bien sûr, surtout pour le big data
      Mais si le PDP-11 a eu du succès et laisse encore des traces aujourd’hui, c’est pour des raisons conceptuelles
    • Ironiquement, on se dirige maintenant vers des machines C avec tagging mémoire matériel
      Parce qu’il n’y a pas d’autre moyen de corriger C, et qu’il y a trop de code qui ne sera jamais réécrit
    • J’ai préféré la fin : « Le réécrire en Rust ? Surtout pas ! Réécrivez-le en Lisp ! »
    • Lisp n’est pas adapté aux CPU modernes à cause de la hiérarchie mémoire
      Lisp manipule surtout des listes, et les listes peuvent amener à suivre des pointeurs éparpillés partout en mémoire
      Sur les anciens CPU, ce n’était pas un problème parce que la mémoire avait globalement les mêmes temps d’accès aléatoires, mais les CPU modernes ne peuvent pas suivre les pointeurs mémoire à la même vitesse et doivent respecter des règles de localité pour les performances
      C’est pourquoi les algorithmes utilisant des choses comme des tableaux en C ou en Fortran seront toujours plus rapides que leurs versions fondées sur des listes Lisp
  • Les progrès récents de Guile Scheme sont encourageants
    Contrairement à la dernière fois que j’avais regardé, c’est devenu un langage interprété avec un vrai compilateur, et il est maintenant possible de compiler vers WASM avec Hoot
    Je connais bien Clojure, uLisp et Common Lisp, mais Guile Scheme me donne l’impression d’un Common Lisp allégé de beaucoup de lourdeurs, et surtout, si Guix et Shepard s’installent durablement, j’aimerais avoir sous la main un Lisp compilé
    Je me demande s’il existe de bonnes ressources pour apprendre efficacement Guile Scheme en dehors de Little Lisper et de SICP

  • Lecture intéressante, car je pense utiliser Guile pour ce que je vais construire ensuite
    Le travail côté WASM a aussi l’air réussi

  • J’ai récemment créé un prototype de combat de boss en 3D avec Clojure : https://prototype-game.pages.dev

    • Excellent
      Avant, je détestais le développement web sous toutes ses formes, mais ClojureScript l’a réellement rendu plaisant, et j’aimerais que ce soit plus largement utilisé
    • Les commandes ne fonctionnent pas sur mobile
      Je réessaierai plus tard quand je serai devant un PC
    • Très sympa
      Je suis curieux de savoir quelles bibliothèques sont utilisées
    • Pour parler avec affection de ce que tu as fait, ça me fait penser à Avatar - Legends of the Arena
      C’était vraiment l’un des jeux que je préférais quand j’étais enfant
      https://www.youtube.com/watch?v=dcJFldES9dg
  • J’avais bien demandé à ce qu’on l’ajoute au tableau, mais c’est peut-être déjà une vieille nouvelle maintenant
    Référence :
    https://lispy-gopher-show.itch.io/logos-lisp-legend/devlog/7...
    https://itch.io/post/10013482

  • Janet est absent alors qu’il y a https://ianthehenry.com/posts/janet-game/
    Le texte affiche une année de copyright 1899~1907, mais c’est dommage que l’ensemble n’ait pas un aspect vintage

    • On dirait bien que Janet a été oublié
      Je suis finalement revenu à Fennel pour le scripting, parce qu’on peut utiliser directement bien plus de bibliothèques Lua, et que ça tourne à peu près partout sans problème, même dans a-Shell sur iPad
    • J’ai envisagé Janet très sérieusement, mais je ne voyais pas de voie directe vers mon objectif, qui était d’utiliser des applications web et WebGL (ThreeJS)
      Il y avait des références utiles dans ce fil, donc je pourrai peut-être réessayer plus tard : https://janet.zulipchat.com/#narrow/stream/409517-help/topic...
      Même avec un parcours de production déjà éprouvé, j’ai tout juste réussi à faire quelque chose de jouable à temps, et le terme « jouable » est déjà un peu généreux
  • Je suis très curieux de savoir quels jeux ont été créés en Emacs Lisp
    Ce n’est pas le premier choix qui vient à l’esprit quand on pense à la programmation de jeux