Tu ne peux pas copier une fonction avec sa scope, juste la passer par référence.
Et tu n'as jamais pu le faire. Les Worker sont l'exemple parfait du fait que tu ne puisse pas copier une fonction.
C'est comme en C, tu as des pointeurs de fonctions, que tu peux copier, mais pas la fonction en elle même.
En Erlang / Elixir, tu as 2 types de fonctions :
les fonctions anonymes, qui peuvent être copiée et stockée dans un ETS/DETS/Mnesia, envoyé a un autre node du cluster pour être exécutée la bas, AVEC sa scope
les fonctions définies dans un module, et la tu les "copie" en passant le tuple {Module, Function, Arguments} ou Module et Function sont des atoms.
Alors oui, assigner une fonction (sa référence) à une variable te permet d'avoir des fonctions d'ordre supérieur et de faire de la programmation fonctionnelle, mais non ça ne fait pas de ton langage un langage fonctionnel.
langage fonctionnel et programmation fonctionnelle
Dans un langage objet, tout est objet, tu n'as pas de type primitifs (1 et true et "hello" sont des objets, pas des valeurs primitives).
Dans un langage fonctionnel, les données sont immutables et les fonctions sont des données.
En Javascript, tu ne peux pas passer une fonction en tant que valeur à un Worker (thread/process) par exemple. Ce qui veut dire que la fonction n'est pas une valeur. Ce n'est donc pas un langage fonctionnel.
Toujours en Javascript, 1 n'est pas un objet, ce n'est donc pas un langage objet.
Cela n'empêche pas d'appliquer du mieux qu'on peut les concepts de ces 2 paradigmes.
A ma connaissance, seul Smalltalk est un vrai langage objet (le code en lui même est un objet que tu peux manipuler).
Concernant les langages fonctionnels, on va identifier 2 types :
purement fonctionnel (les effets de bords sont abstrait par le runtime) : Haskell / Purescript
les autres : Erlang / Elixir
Et donc par cette définition, non ni Javascript, ni Go, ni Python, ni C++, ni beaucoup de langages ne sont "objets" ou "fonctionnels". Ultimement tout ces langages se retrouvent exécuté par un CPU, donc représenté d'une manière ou d'une autre par une suite d'instruction assembleur. Donc a partir du moment ou ton langage est Turing-Complete, tu peux réutiliser ces paradigmes.
En Go, tu peux passer des fonctions en argument à d'autres, ce qui implique que tu as des fonctions d'ordre supérieur. Avec les generics de Go 1.18 on voit apparaître des patterns typique de la programmation fonctionnelle (cf les 2 liens que j'ai cité avec l'implémentation des map/filter/reduce/…).
La POO c'est le concept d'encapsulation des données pour présenter une API (les méthodes) pour les manipuler. A ce que je sache, Go permet cela avec les structures et les fonctions qui prennent un paramètre "receiver".
De plus, les interfaces de Go permettent d'avoir du polymorphisme.
La programmation fonctionnelle, c'est l'art d'organiser son code autour de fonctions, de closures, et de combinators. Toutes ces choses sont possible en Go.
Dans le domaine du jeu vidéo, on voit apparaître depuis 10-15 ans un retour vers la programmation fonctionnelle (qui est très vieille), notamment avec le concept de Data-Oriented Design et les Entity Component System.
La programmation orienté objet s'est faite malmenée en entreprise. J'entends par la que les paradigmes initiaux ont été détourné de telle sorte qu'elle ne tient plus ses promesses (réutilisation du code).
J'en profite pour citer sans connaître l'auteur original :
En POO, si tu veux une banane, tu dois ajouter le gorille qui tient la banane et toute la forêt.
Sauf que POO et Programmation Fonctionnelle ne sont pas incompatible. Prenons l'exemple de Go (ugh, qu'est-ce que je déteste ce langage trop pratique…). Il y a des interfaces, des structures, des méthodes. Pas d'héritage, que de la composition. C'est suffisant pour implémenter de l'injection de dépendance, pattern très utilisé en programmation fonctionnelle pour découpler le business code de l'implémentation.
Les ECS en gamedev sont aussi une forme d'injection de dépendance, ajouter un composant (uniquement des data) à une entité (uniquement un id) lui ajoute de la fonctionnalité via les systèmes (uniquement de l'implémentation).
Cette découpe est non seulement pratique d'un point de vue maintenance du code, mais en plus, elle scale bien.
Et si on reprend l'exemple de la POO dans le monde des entreprises, avec les dizaines de couche d'abstraction pour faire un print, les librairies qui font plus que leur scope initiale (coucou log4shell), ça ne scale pas. On se retrouve 10 ans plus tard avec un monolithe qui mets 45min a build un simple commit.
J'ai même envie de faire le parallèle avec l'infrastructure. Aujourd'hui, les microservices sont au centre d'une grosse hype. L'idée étant d'avoir des briques élémentaires (fonctions, microservices, …) que tu assembles comme des Lego pour construire un système complexe.
Alors oui, les microservices ne répondent que a un problème organisationnel de l'entreprise (comment plusieurs teams peuvent bosser sur le même projet sans se marcher dessus ?), j'ai envie de dire que la programmation fonctionnelle répond à un problème organisationnel du code source (comment plusieurs systèmes peuvent fonctionner en parallèle sans fuite de l'API et avec une bonne "Separation of Concerns").
L'autre raison que je vois à la popularité de la programmation fonctionnelle, c'est :
React/Redux et ses successeurs, dont l'architecture est purement fonctionnelle (l'UI est une fonction qui prend en paramètre le state)
Le plus marrant je trouve la dedans, c'est que la montée en popularité de la programmation fonctionnelle a lieu surtout dans des langages qui ne sont pas fonctionnels :
En fait la continuation va indiquer ce qu'on fait ensuite.
Donc pour parser la ligne const a := 42;, la fonction qui parse const va retourner la fonction qui parse le reste ou une fonction qui retourne une erreur.
Et ainsi de suite, on va parser a et retourner la fonction qui parse le reste.
L'utilisateur va donc pouvoir contrôler quand et à quel rythme l'analyse se déroule. Il peut faire une simple boucle (ou fonction récursive) :
Je l'ai déjà évoqué rapidement dans la première partie, c'est un simple arbre ou chaque noeud contient les informations nécessaire pour passer à la phase suivante.
Ces informations sont complétées au fur et à mesure des différents parcours de l'arbre, produisant à la fin le code source Rust à compiler.
A priori, la forme SSA simplifie la manipulation du code
Je ne connais pas la théorie derrière, c'est la première fois que j'entends le nom de ce concept, la page wikipedia parle du concept de CPS (Continuation Passing Style) qui semble plus utilisé par les langages de programmation fonctionnelle. C'est un concept que j'utilise pas mal pour l'implémentation de protocole TCP (le dernier en date, un subset du protocole de Redis), je trouve cela assez naturel.
Qu'en penses-tu ?
A ce stade, l'AST dans sa forme actuelle me semble suffisant, mais je garde l'article wikipedia sous la main,, on sait jamais je pourrais en avoir besoin :) Merci pour l'info.
Dites les critiques, vous êtes sûrs que vous ne réagissez pas de manière un peu 'instinctive'?
Lorsque l'on propose un changement de syntaxe à un langage, il faut regarder comment ça s'intègre avec le reste du langage.
Par exemple, l'opérateur de pipeline en Elixir:
a|>b()|>c()# vsc(b(a))
Si je voudrais l'ajouter tel quel en C, ça donnerait :
a|>b()|>c()
Mais est-ce que ça a du sens en C ? En C un opérateur s'applique sur des valeurs, or b() n'est pas une valeur.
Du coup, est-ce que a |> b est un pointeur de fonction ? Si oui, cela pointe vers quoi ? Est-ce que cela produit un nouveau symbole dans le .o ?
Toutes ces questions me font répondre que : non, l'opérateur de pipeline n'a pas sa place dans le langage C.
La totalité du langage Lisp repose sur le principe suivant : ( expression ), et f a b c est une expression ou f est une fonction. Ce qui veut dire qu'en Lisp, il n'y a pas d'opérateurs, + est aussi une fonction.
Dans mon exemple, f prend 3 arguments, maintenant pour le second exemple : (g (cons a b c)). Ici g prend un seul argument, une liste, construite avec cons.
On a (defvar a 42), (defun ...), (lambda ...) et (defmacro ...). Tout se ressemble. C'est cohérent. Du coup introduire f(a b c), ça casse la cohérence.
Le Lisp classique a d'ailleurs '(x y) pour l'abbréviation de (quote x y)..
Après m'être documenté, 'x est l'abbréviation de (quote x). Et donc '(x y) devrait être (quote (x y)). Il semble que les différents Lisp (Scheme et compagnie) gèrent ça différemment.
Syncing other resources such as deployments, statefulsets and namespaces is usually not needed as those just control lower level resources and since those lower level resources are synced the cluster can function correctly.
However, there might be cases though were custom syncing of resources might be needed or beneficial. In order to accomplish this, vcluster provides an SDK to develop your own resource syncers as plugins. To find out more, please take a look at the plugins documenation.
Cela veut dire que tu peux créer un opérateur Kubernetes en mode SaaS :
tu installes l'opérateur sur le cluster hôte
tu ajoute tes CRDs au vcluster, ainsi que le plugin pour les synchroniser sur le cluster hôte
tu fournit un vcluster a tes clients, qui peuvent bénéficier de ton opérateur sans devoir gérer l'installation / la mise à jour / …
derrière, tu scale le cluster hôte, ça scale tout le monde
C'est d'autant plus intéressant car vcluster ce n'est pas de la virtualisation (c'est pas KinD - Kubernetes in Docker), c'est juste un niveau d'abstraction supplémentaire pour découper proprement les choses.
Tu peux utiliser des templates dans une macro, et simplement convertir la le résultat avec TokenStream::parse a la fin
Ah effectivement, ça peut être intéressant.
L'aventage de la macro comparé a apeller rust toi même c'est que ça s'intègre avec cargo qui gère les flag compliqué pour toi comme la cross compilation, le compilation incrementale, et que sais-je.
A terme, j'aimerais bien que mon compilo soit self-hosted (écrire letlang en letlang). Du coup je vais finir par devoir les gérer moi même ces flags, non ?
L'idée est qu'il n'y a pas de main.rs. Uniquement un Cargo.toml qui dit a cargo d'ouvrir lui même (a cause du path = "Cargo.toml") et de simplement apeller ta macro qui fait le reste.
Tant qu'a générer du Rust, tu peux aussi utiliser des macro procédurale.
Idée intéressante, mais je trouve qu'utiliser des templates est moins capilo-tracté que manipuler le TokenStream de Rust. J'ai jamais réussi à faire ce que je veux avec les macros de Rust, je les trouve atroces.
Mais bon, ça c'est parce que mon langage préféré, Elixir, a juste la meilleure syntaxe du monde (totalement subjectif, totalement assumé) pour les macros :)
Pour les erreurs, je suggère codemap-diagnostic
Excellent ! Je garde de côté, merci :)
tu pourrait avoir un self-contained Cargo.toml (qui est à la fois valid toml et rust) comme fichier pour le build système:
J'ai pas compris l'exemple, ce code irait dans le main.rs du projet ? Et il est censé faire quoi ?
Le lisp c'est très bien. Paraîtrait même que c'est le papa de nombreuses fonctionnalités que tu retrouves dans quasiment tout les langages. Rust inclus.
Seulement voilà, je n'ai jamais écrit une ligne de Lisp. Donc l'idée ne m'a pas traversé l'esprit. Et maintenant que tu en parles, non je ne pense pas que cela serait mon choix. Rust apporte des garanties de sécurité de la mémoire qui sont trop intéressante.
Et puis le plus important je pense : je veux progresser en Rust.
ne crains-tu pas qu'au niveau des messages on se retrouve un peu loin des paradigmes du langage initial ?
Je prévois une compilation en plusieurs phases :
Phase 0: l'analyse lexicale transforme le texte en "Token Stream"
Phase 1: l'analyse syntaxique transforme le "Token Stream" en un AST annoté de metadata (nom du fichier, ligne, colonne, token, …)
Phase 2: l'analyse sémantique parcours ce premier AST pour vérifier le respect des règles du langage
Phase 3: l'analyse statique parcours à nouveau l'AST pour vérifier la cohérence des types du mieux qu'il peut, ainsi que l'inférence de type quand c'est possible
Phase 4: le compilateur traduit l'AST annoté par les 2 phases précédentes en langage Rust
Phase 5: appel du compilateur Rust
Mon hypothèse, c'est qu'une fois arrivée à l'etape 4, on a la garantie que le code Rust produit ne générera pas d'erreur de compilation.
Les éléments qui me permettent de soutenir cette hypothèse sont :
l'AST consommé par l'étape 4 est censé avoir toutes les informations nécessaire pour produire un code complet
le code produit par les différents noeuds de l'AST a été testé en amont (un Literal::Number va toujours produire le même code)
l'AST garanti qu'on ne trouvera pas un "bloc de fonction" utilisé comme string literal pour un import, donc le code Rust produit reflète cet aspect aussi, on ne peut trouver que du code Rust valide dans le contexte/scope ou il est produit car c'est comme ça que l'implémentation aura été faite
En fait, c'est comme se demander : que se passe-t-il si après avoir compilé le C en ASM, l'assembleur renvoi une erreur ? Le soucis est au niveau de GCC ici, pas au niveau du code que je lui fournit.
Maintenant, que mon hypothèse est posée, l'implémentation suivi par les tests la confirmera ou l'infirmera.
A ce moment là, je peux toujours identifier grâce au message d'erreur de rustc quel est le bout de code qui produit l'erreur, et grâce aux annotations de l'AST produites en phase 0 à 3, retrouver le code Letlang concerné.
NB: Dans ce journal, j'explique comment j'ai commencé l'implémentation de la phase 4 et 5, en construisant à la main l'AST "valide".
J'ai fait il y a quelques temps une grammaire pest pour la phase 0 et 1. Mais comme je change d'avis sur la syntaxe comme je change de chemise, c'était contre productif.
Par contre, l'AST lui risque pas de bouger beaucoup, après tout, les concepts sont la, et les informations dont j'ai besoin pour les représenter aussi. Au final, commencer par la phase 4 et 5 c'est plus simple, et ça me fournit une suite de test pour implémenter les phases précédentes.
Finalement, Letlang est devenu un (r)habillage de Rust avec ton déclic (:
Au final, tout les langages ne sont ils pas un rhabillage du langage cible (javascript pour typescript, erlang pour elixir, …) ? (:
J'ai plus confiance dans ma capacité à implémenter ce que je souhaite en Rust qu'en LLVM IR ou Assembleur.
Et j'ai plus confiance dans le résultat que cela va produire. Il me semble que débugger du Rust sera plus simple que débugger du LLVM IR.
Je ne pense pas que les devs de Qt company soit sous l'emprise de champignons hallucinogènes.
Source ?
De plus je ne trouve pas dans la doc la moindre explication sur l'implémentation du moteur de rendu. Il faut utiliser une Image pour faire de l'OpenGL ?
Dans la doc de Gio UI, on trouve la ligne suivante :
app.NewWindow chooses the appropriate “driver” depending on the environment and build context. It might choose Wayland, Win32, Cocoa among several others.
J'ai pas regardé pour Fyne, mais c'est pas déconnant pour une appli native soit d'utiliser OpenGL (portable) soit un moyen de détecter l'api native comme Gio UI.
En lisant la survey, ils manquent des aspects essentiels pour une UI. Je me demande franchement qu'elle ait l'expérience de ces gens en la matière.
Quels aspects essentiels ? Qui es-tu pour juger l'expérience des gens, toi qui ne sait pas ouvrir un Bescherelle.
Quant au binding Qt. Il n'y a pas eu un commit depuis 2 ans. Et ça n'a aucun sens si le binding n'est pas autogénéré comme PyQt/PySide.
Ou alors l'ABI a pas changé depuis, hmm?
Pour les UI en techno web sur browser, React est à mon avis une des meilleures solutions.
Encore une fois, ce n'est que ton avis. Il y a Flutter, Angular, VueJS, Knockout, du SSR rendering avec Django/Flask, ou Elixir/Phoenix LiveView, … Il y a le bon vieux site statique, les Web Components, etc… Toute une myriade de solutions pour une myriade de besoins différents, et personne ne peut objectivement dire que l'une est la meilleure.
Mais Redux me donne des migraines au cerveau.
Ok. Je vois pas ce que ça apporte à l'argumentation.
Le seul avantage, c'est quand la puissance du CSS apporte une valeur ajoutée, par exemple si on veut afficher une typographie à la Wikipédia dans une application. cf. Qt Rich Text.
Tu passes du Coq à l'Ane, et aucun n'est à la bière. La possibilité de personnaliser une interface est quelque chose de très demandé par les designers depuis très longtemps. GTK 3 a introduit le CSS pour ses widgets pour remplacer les GtkStyle de GTK 2, et on a la même chose côté Qt. Ca fait quoi, 15-20 ans ?
Être aussi réducteur sur une technologie, je comprends pas l'intérêt.
Donc yet another UI…
Donc yet another commentaire trollesque qui donne son avis sans aucun argument.
Ça ne m'étonne pas. Dans le monde du gamedev tu retrouvera beaucoup :
C++ (Ogre, Irrlicht, Unreal Engine, Cryengine, …)
C# (Cryengine, Hazel, Unity, …)
Godot est développé en C++ et introduit GDScript (qui ressemble a Python), et gagne en popularité. Donc charger une DLL pour étendre les fonctionnalités de l'engine n'est pas très complexe. Pareil pour GameMaker Studio.
Donc avoir un SDK en C, c'est s'assurer de pouvoir intégrer à toutes ces engines de manière assez simple.
Pourquoi le C est plus simple à intégrer que le C++ ? C'est une question d'ABI. En C++ tu as ce qu'on appelle le name mangling, donc tu peux pas juste naïvement faire un dlopen / dlsym.
Pardon, j'aurais du dire "le logiciel n'est pas libre". En effet si on considère que "le logiciel" englobe son code et son nom et ses assets.
Vu qu'il y a des conditions sur ce que tu peux distribuer, c'est pas 100% libre.
Pour l'exemple opposé, on a Python ou Debian a continué la branche 2.7 bien plus longtemps que upstream (2.7.18-13 étant la dernière en date). Et ils ont droit de l'appeler Python.
Le code est libre, mais la marque ne l'est pas. Et ça ne me choque pas
Moi non plus ça ne me choque pas. Ce qui me choque c'est que cela soit utilisé comme argument détracteur de Debian, alors que le principe même de Debian c'est de ne pas accepter un quelconque truc propriétaire (que cela soit un nom, une image, ou un bout de code).
On adhère à cette philosophie, ou on adhère pas, c'est pas le sujet.
[^] # Re: Première partie
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust (partie 2). Évalué à 3.
Merci :) j'oublierai pas de lier la partie 3 ici ^
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: J'ai pas écouté le podcast, mais mon grain de sel
Posté par David Delassus (site web personnel) . En réponse au lien Is functional programming the hipster programming paradigm?. Évalué à 4.
Tu ne peux pas copier une fonction avec sa scope, juste la passer par référence.
Et tu n'as jamais pu le faire. Les Worker sont l'exemple parfait du fait que tu ne puisse pas copier une fonction.
C'est comme en C, tu as des pointeurs de fonctions, que tu peux copier, mais pas la fonction en elle même.
En Erlang / Elixir, tu as 2 types de fonctions :
{Module, Function, Arguments}
ouModule
etFunction
sont des atoms.Alors oui, assigner une fonction (sa référence) à une variable te permet d'avoir des fonctions d'ordre supérieur et de faire de la programmation fonctionnelle, mais non ça ne fait pas de ton langage un langage fonctionnel.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: J'ai pas écouté le podcast, mais mon grain de sel
Posté par David Delassus (site web personnel) . En réponse au lien Is functional programming the hipster programming paradigm?. Évalué à 3.
Parce que je fais la différence entre :
Dans un langage objet, tout est objet, tu n'as pas de type primitifs (
1
ettrue
et"hello"
sont des objets, pas des valeurs primitives).Dans un langage fonctionnel, les données sont immutables et les fonctions sont des données.
En Javascript, tu ne peux pas passer une fonction en tant que valeur à un Worker (thread/process) par exemple. Ce qui veut dire que la fonction n'est pas une valeur. Ce n'est donc pas un langage fonctionnel.
Toujours en Javascript,
1
n'est pas un objet, ce n'est donc pas un langage objet.Cela n'empêche pas d'appliquer du mieux qu'on peut les concepts de ces 2 paradigmes.
A ma connaissance, seul Smalltalk est un vrai langage objet (le code en lui même est un objet que tu peux manipuler).
Concernant les langages fonctionnels, on va identifier 2 types :
Et donc par cette définition, non ni Javascript, ni Go, ni Python, ni C++, ni beaucoup de langages ne sont "objets" ou "fonctionnels". Ultimement tout ces langages se retrouvent exécuté par un CPU, donc représenté d'une manière ou d'une autre par une suite d'instruction assembleur. Donc a partir du moment ou ton langage est Turing-Complete, tu peux réutiliser ces paradigmes.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: J'ai pas écouté le podcast, mais mon grain de sel
Posté par David Delassus (site web personnel) . En réponse au lien Is functional programming the hipster programming paradigm?. Évalué à 6.
En Go, tu peux passer des fonctions en argument à d'autres, ce qui implique que tu as des fonctions d'ordre supérieur. Avec les generics de Go 1.18 on voit apparaître des patterns typique de la programmation fonctionnelle (cf les 2 liens que j'ai cité avec l'implémentation des map/filter/reduce/…).
La POO c'est le concept d'encapsulation des données pour présenter une API (les méthodes) pour les manipuler. A ce que je sache, Go permet cela avec les structures et les fonctions qui prennent un paramètre "receiver".
De plus, les interfaces de Go permettent d'avoir du polymorphisme.
La programmation fonctionnelle, c'est l'art d'organiser son code autour de fonctions, de closures, et de combinators. Toutes ces choses sont possible en Go.
Tu peux aussi faire de la POO en C : https://www.cs.rit.edu/~ats/books/ooc.pdf
Pas si ballot que ça du coup, vu que c'est le parfait exemple d'un langage qui permet de marier les 2 concepts.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# J'ai pas écouté le podcast, mais mon grain de sel
Posté par David Delassus (site web personnel) . En réponse au lien Is functional programming the hipster programming paradigm?. Évalué à 8.
Dans le domaine du jeu vidéo, on voit apparaître depuis 10-15 ans un retour vers la programmation fonctionnelle (qui est très vieille), notamment avec le concept de Data-Oriented Design et les Entity Component System.
La programmation orienté objet s'est faite malmenée en entreprise. J'entends par la que les paradigmes initiaux ont été détourné de telle sorte qu'elle ne tient plus ses promesses (réutilisation du code).
J'en profite pour citer sans connaître l'auteur original :
Sauf que POO et Programmation Fonctionnelle ne sont pas incompatible. Prenons l'exemple de Go (ugh, qu'est-ce que je déteste ce langage trop pratique…). Il y a des interfaces, des structures, des méthodes. Pas d'héritage, que de la composition. C'est suffisant pour implémenter de l'injection de dépendance, pattern très utilisé en programmation fonctionnelle pour découpler le business code de l'implémentation.
Les ECS en gamedev sont aussi une forme d'injection de dépendance, ajouter un composant (uniquement des data) à une entité (uniquement un id) lui ajoute de la fonctionnalité via les systèmes (uniquement de l'implémentation).
Cette découpe est non seulement pratique d'un point de vue maintenance du code, mais en plus, elle scale bien.
Et si on reprend l'exemple de la POO dans le monde des entreprises, avec les dizaines de couche d'abstraction pour faire un print, les librairies qui font plus que leur scope initiale (coucou log4shell), ça ne scale pas. On se retrouve 10 ans plus tard avec un monolithe qui mets 45min a build un simple commit.
J'ai même envie de faire le parallèle avec l'infrastructure. Aujourd'hui, les microservices sont au centre d'une grosse hype. L'idée étant d'avoir des briques élémentaires (fonctions, microservices, …) que tu assembles comme des Lego pour construire un système complexe.
Alors oui, les microservices ne répondent que a un problème organisationnel de l'entreprise (comment plusieurs teams peuvent bosser sur le même projet sans se marcher dessus ?), j'ai envie de dire que la programmation fonctionnelle répond à un problème organisationnel du code source (comment plusieurs systèmes peuvent fonctionner en parallèle sans fuite de l'API et avec une bonne "Separation of Concerns").
L'autre raison que je vois à la popularité de la programmation fonctionnelle, c'est :
Le plus marrant je trouve la dedans, c'est que la montée en popularité de la programmation fonctionnelle a lieu surtout dans des langages qui ne sont pas fonctionnels :
Alors qu'il y a OCaml, Elixir, Haskell, Purescript (si tu veux compiler en du Haskell en JS), etc…
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: super article !
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust (partie 2). Évalué à 6.
En fait la continuation va indiquer ce qu'on fait ensuite.
Donc pour parser la ligne
const a := 42;
, la fonction qui parseconst
va retourner la fonction qui parse le reste ou une fonction qui retourne une erreur.Et ainsi de suite, on va parser
a
et retourner la fonction qui parse le reste.L'utilisateur va donc pouvoir contrôler quand et à quel rythme l'analyse se déroule. Il peut faire une simple boucle (ou fonction récursive) :
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Erreurs
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust (partie 2). Évalué à 5.
Ça se tient.
Tu remarqueras cependant qu'aucun compilo/interpréteur ne fait la différence, ils appellent les deux une erreur de syntaxe. D'où ma confusion.
Pour ma part, j'utilise le type "ParseError" et "CompilationError", donc je fais même pas la différence avec l'erreur sémantique.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: super article !
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust (partie 2). Évalué à 4.
Merci pour ton retour :)
Je l'ai déjà évoqué rapidement dans la première partie, c'est un simple arbre ou chaque noeud contient les informations nécessaire pour passer à la phase suivante.
Ces informations sont complétées au fur et à mesure des différents parcours de l'arbre, produisant à la fin le code source Rust à compiler.
Je ne connais pas la théorie derrière, c'est la première fois que j'entends le nom de ce concept, la page wikipedia parle du concept de CPS (Continuation Passing Style) qui semble plus utilisé par les langages de programmation fonctionnelle. C'est un concept que j'utilise pas mal pour l'implémentation de protocole TCP (le dernier en date, un subset du protocole de Redis), je trouve cela assez naturel.
A ce stade, l'AST dans sa forme actuelle me semble suffisant, mais je garde l'article wikipedia sous la main,, on sait jamais je pourrais en avoir besoin :) Merci pour l'info.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# Trop dur d'attendre Vendredi
Posté par David Delassus (site web personnel) . En réponse au lien Vim users be like:. Évalué à 3.
Emacs users be like
https://www.reddit.com/r/vim/comments/l9hv5k/emacs_users_be_like/
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: lisp ?
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 3.
Lorsque l'on propose un changement de syntaxe à un langage, il faut regarder comment ça s'intègre avec le reste du langage.
Par exemple, l'opérateur de pipeline en Elixir:
Si je voudrais l'ajouter tel quel en C, ça donnerait :
Mais est-ce que ça a du sens en C ? En C un opérateur s'applique sur des valeurs, or
b()
n'est pas une valeur.Du coup, est-ce que
a |> b
est un pointeur de fonction ? Si oui, cela pointe vers quoi ? Est-ce que cela produit un nouveau symbole dans le.o
?Toutes ces questions me font répondre que : non, l'opérateur de pipeline n'a pas sa place dans le langage C.
La totalité du langage Lisp repose sur le principe suivant :
( expression )
, etf a b c
est une expression ouf
est une fonction. Ce qui veut dire qu'en Lisp, il n'y a pas d'opérateurs,+
est aussi une fonction.Dans mon exemple,
f
prend 3 arguments, maintenant pour le second exemple :(g (cons a b c))
. Icig
prend un seul argument, une liste, construite aveccons
.On a
(defvar a 42)
,(defun ...)
,(lambda ...)
et(defmacro ...)
. Tout se ressemble. C'est cohérent. Du coup introduiref(a b c)
, ça casse la cohérence.Après m'être documenté,
'x
est l'abbréviation de(quote x)
. Et donc'(x y)
devrait être(quote (x y))
. Il semble que les différents Lisp (Scheme et compagnie) gèrent ça différemment.cf: https://stackoverflow.com/a/20643658/1020897
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: lisp ?
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 3.
Le meilleur exemple "non-lisp" (entre grosses guillemets) c'est les templates Go :
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: toy ?
Posté par David Delassus (site web personnel) . En réponse au lien Un Kubernetes dans un Kubernetes dans un Kubernetes dans un Kubernetes dans un Kubernetes dans.... Évalué à 4.
Je suis pas vraiment d'accord. L'intérêt d'un cluster dans un namespace c'est plusieurs choses :
De plus : https://www.vcluster.com/docs/architecture/synced-resources#sync-other-resources
Cela veut dire que tu peux créer un opérateur Kubernetes en mode SaaS :
C'est d'autant plus intéressant car vcluster ce n'est pas de la virtualisation (c'est pas KinD - Kubernetes in Docker), c'est juste un niveau d'abstraction supplémentaire pour découper proprement les choses.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Générer du Rust
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 3.
Ah effectivement, ça peut être intéressant.
A terme, j'aimerais bien que mon compilo soit self-hosted (écrire letlang en letlang). Du coup je vais finir par devoir les gérer moi même ces flags, non ?
Fun, je vais regarder ça de plus près.
Merci pour tes retours.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Générer du Rust
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 4.
Idée intéressante, mais je trouve qu'utiliser des templates est moins capilo-tracté que manipuler le TokenStream de Rust. J'ai jamais réussi à faire ce que je veux avec les macros de Rust, je les trouve atroces.
Mais bon, ça c'est parce que mon langage préféré, Elixir, a juste la meilleure syntaxe du monde (totalement subjectif, totalement assumé) pour les macros :)
Excellent ! Je garde de côté, merci :)
J'ai pas compris l'exemple, ce code irait dans le main.rs du projet ? Et il est censé faire quoi ?
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: lisp ?
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 4.
Rust est memory safe sans GC.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# Ca poutre
Posté par David Delassus (site web personnel) . En réponse au lien Un Kubernetes dans un Kubernetes dans un Kubernetes dans un Kubernetes dans un Kubernetes dans.... Évalué à 2. Dernière modification le 08 mars 2022 à 09:14.
J'ai eu l'occasion de bosser avec pour mettre en place une infra multi-tennant. C'est une tuerie.
Il manquait une seule chose à l'époque : la possibilité de sélectionner quelles ressources sont répliquées sur le cluster hôte.
Cela permettrait de mutualiser des opérateurs comme TektonCD, ou même celui que he développe Kubirds.
Faudra que j'aille zieuter si ça a changé.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: lisp ?
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 2.
Le lisp c'est très bien. Paraîtrait même que c'est le papa de nombreuses fonctionnalités que tu retrouves dans quasiment tout les langages. Rust inclus.
Seulement voilà, je n'ai jamais écrit une ligne de Lisp. Donc l'idée ne m'a pas traversé l'esprit. Et maintenant que tu en parles, non je ne pense pas que cela serait mon choix. Rust apporte des garanties de sécurité de la mémoire qui sont trop intéressante.
Et puis le plus important je pense : je veux progresser en Rust.
Accessoirement:
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: j'en dis que
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 2.
Je prévois une compilation en plusieurs phases :
Mon hypothèse, c'est qu'une fois arrivée à l'etape 4, on a la garantie que le code Rust produit ne générera pas d'erreur de compilation.
Les éléments qui me permettent de soutenir cette hypothèse sont :
En fait, c'est comme se demander : que se passe-t-il si après avoir compilé le C en ASM, l'assembleur renvoi une erreur ? Le soucis est au niveau de GCC ici, pas au niveau du code que je lui fournit.
Maintenant, que mon hypothèse est posée, l'implémentation suivi par les tests la confirmera ou l'infirmera.
A ce moment là, je peux toujours identifier grâce au message d'erreur de
rustc
quel est le bout de code qui produit l'erreur, et grâce aux annotations de l'AST produites en phase 0 à 3, retrouver le code Letlang concerné.NB: Dans ce journal, j'explique comment j'ai commencé l'implémentation de la phase 4 et 5, en construisant à la main l'AST "valide".
J'ai fait il y a quelques temps une grammaire pest pour la phase 0 et 1. Mais comme je change d'avis sur la syntaxe comme je change de chemise, c'était contre productif.
Par contre, l'AST lui risque pas de bouger beaucoup, après tout, les concepts sont la, et les informations dont j'ai besoin pour les représenter aussi. Au final, commencer par la phase 4 et 5 c'est plus simple, et ça me fournit une suite de test pour implémenter les phases précédentes.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: corrections listes
Posté par David Delassus (site web personnel) . En réponse au journal démat' arch' fort. Évalué à 2.
Ha! Je suis pas tout seul à me foirer sur la relecture :)
Faut ptet qu'on arrête d'écrire après 23h.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: j'en dis que
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust. Évalué à 2. Dernière modification le 08 mars 2022 à 03:01.
Ah! Si un modo passe par la:
Au final, tout les langages ne sont ils pas un rhabillage du langage cible (javascript pour typescript, erlang pour elixir, …) ? (:
J'ai plus confiance dans ma capacité à implémenter ce que je souhaite en Rust qu'en LLVM IR ou Assembleur.
Et j'ai plus confiance dans le résultat que cela va produire. Il me semble que débugger du Rust sera plus simple que débugger du LLVM IR.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# Playonlinux
Posté par David Delassus (site web personnel) . En réponse au lien Bottles, un frontend à WINE. Évalué à 2.
Cela me rappelle un peu PlayOnLinux.
C'est quoi les grosses différences ?
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Go with C
Posté par David Delassus (site web personnel) . En réponse au journal Interface graphique en Go!. Évalué à 1.
On joue a trouver des proverbes à la con pour se lancer des fions ?
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Mais ou est l'innovation ???
Posté par David Delassus (site web personnel) . En réponse au journal Interface graphique en Go!. Évalué à 6.
Source ?
Ce n'est pas un argument.
Source ?
Dans la doc de Gio UI, on trouve la ligne suivante :
J'ai pas regardé pour Fyne, mais c'est pas déconnant pour une appli native soit d'utiliser OpenGL (portable) soit un moyen de détecter l'api native comme Gio UI.
Quels aspects essentiels ? Qui es-tu pour juger l'expérience des gens, toi qui ne sait pas ouvrir un Bescherelle.
Ou alors l'ABI a pas changé depuis, hmm?
Encore une fois, ce n'est que ton avis. Il y a Flutter, Angular, VueJS, Knockout, du SSR rendering avec Django/Flask, ou Elixir/Phoenix LiveView, … Il y a le bon vieux site statique, les Web Components, etc… Toute une myriade de solutions pour une myriade de besoins différents, et personne ne peut objectivement dire que l'une est la meilleure.
Ok. Je vois pas ce que ça apporte à l'argumentation.
Tu passes du Coq à l'Ane, et aucun n'est à la bière. La possibilité de personnaliser une interface est quelque chose de très demandé par les designers depuis très longtemps. GTK 3 a introduit le CSS pour ses widgets pour remplacer les GtkStyle de GTK 2, et on a la même chose côté Qt. Ca fait quoi, 15-20 ans ?
Être aussi réducteur sur une technologie, je comprends pas l'intérêt.
Donc yet another commentaire trollesque qui donne son avis sans aucun argument.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Valve fait du C
Posté par David Delassus (site web personnel) . En réponse au journal C, un âge remarquable. Évalué à 4.
Ça ne m'étonne pas. Dans le monde du gamedev tu retrouvera beaucoup :
Godot est développé en C++ et introduit GDScript (qui ressemble a Python), et gagne en popularité. Donc charger une DLL pour étendre les fonctionnalités de l'engine n'est pas très complexe. Pareil pour GameMaker Studio.
Donc avoir un SDK en C, c'est s'assurer de pouvoir intégrer à toutes ces engines de manière assez simple.
Pourquoi le C est plus simple à intégrer que le C++ ? C'est une question d'ABI. En C++ tu as ce qu'on appelle le name mangling, donc tu peux pas juste naïvement faire un
dlopen
/dlsym
.https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Go with C
Posté par David Delassus (site web personnel) . En réponse au journal Interface graphique en Go!. Évalué à 2. Dernière modification le 04 mars 2022 à 20:28.
Pardon, j'aurais du dire "le logiciel n'est pas libre". En effet si on considère que "le logiciel" englobe son code et son nom et ses assets.
Vu qu'il y a des conditions sur ce que tu peux distribuer, c'est pas 100% libre.
Pour l'exemple opposé, on a Python ou Debian a continué la branche 2.7 bien plus longtemps que upstream (2.7.18-13 étant la dernière en date). Et ils ont droit de l'appeler Python.
Moi non plus ça ne me choque pas. Ce qui me choque c'est que cela soit utilisé comme argument détracteur de Debian, alors que le principe même de Debian c'est de ne pas accepter un quelconque truc propriétaire (que cela soit un nom, une image, ou un bout de code).
On adhère à cette philosophie, ou on adhère pas, c'est pas le sujet.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg