ylsul a écrit 222 commentaires

  • [^] # Re: Uber, Lebonrecel, Airbnb : pas de le l'économie collaborative

    Posté par  . En réponse au journal Le Bon Coin, Airbnb, Uber : Les prochaines poules aux œufs d'or. Évalué à 3.

    En l'occurrence il s'agit de taxer pareil des activités qui se déplacent ou qui sont nouvelles mais qui sont de mêmes natures que des précédentes (commerce).

    La distinction entre les uns et "les autres" je ne vois pas à quoi ça correspond : il existe différentes mesures pour lutter contre les activités au noir, ce n'est pas parfait, c'est comme ça… Ceux qui sont touchés par une mesure peuvent toujours dire "mais on n'a pas traité parfaitement tous les autres avant nous", mais bon…

  • [^] # Re: Uber, Lebonrecel, Airbnb : pas de le l'économie collaborative

    Posté par  . En réponse au journal Le Bon Coin, Airbnb, Uber : Les prochaines poules aux œufs d'or. Évalué à 1.

    C'est curieux, je pensais que la TVA était incluse dans les frais de douane. Tu es sûr de comment ça marche (c'est un vrai exemple et tu ne t'es pas trompé) ou c'est juste une explication ?

    Que les frais de douane s'appliquent sur le prix de l'objet c'est assez normal : si tu passes un carton deux fois moins gros contenant de petits objets tu paies deux fois moins. Plus la fraude possible notée dans le commentaire au-dessus. Et dans cette somme tu paies aussi des frais de douane sur des frais de transports des pièces détachées de ton objet, payées par l'entreprise qui l'assemble et qui te le refacture dans le prix. Je ne vois pas trop de différence avec les frais d'acheminement dans ton pays.

    Pour le second scandale : j'aimerais bien vérifier ça, je suis curieux. Et même si c'est vrai ça n'a rien d'un scandale : on peut prélever la même somme en appliquant la TVA et un pourcentage plus élevé de droits de douane, séparément ; est-ce que du coup ce serait moins un scandale ? Ce qui est important c'est combien on prélève sur l'activité économique, à quel moment, … C'est plus lisible quand c'est plus simple mais le fait qu'il y ait un prélèvement sur un prélèvement n'a rien d'un scandale. D'un point de vue financier (sommes prélevées) on s'en fiche comme je l'ai expliqué juste avant ; s'il s'agit de savoir à quels problèmes ça répond et pourquoi c'est comme ça ben on n'est pas plus avancé parce que tu n'as pas cherché à le savoir… Note qu'une fois qu'on a un peu creusé le sujet on peut penser que la raison est mauvaise, mais avant il faut bien comprendre comment ça marche et pourquoi.

  • [^] # Re: Juste milieu ?

    Posté par  . En réponse au journal Le Bon Coin, Airbnb, Uber : Les prochaines poules aux œufs d'or. Évalué à 2.

    Après une recherche très rapide, les premiers trucs que j'ai trouvés (un officiel et l'autre plus détaillé) :
    http://www.economie.gouv.fr/files/files/directions_services/dgfip/controle_fiscal/procedes_fraude/4_Tva_marge_et_biens_occasion.pdf
    http://www.entreprises.cci-paris-idf.fr/web/reglementation/developpement-entreprise/droit-fiscal/regime-tva-biens-occasion

    Si je comprends bien la TVA serait payée sur la valeur ajoutée (!) : le service de revente que tu fournis. Ce qui paraît logique : tu as ajouté une valeur à ce produit (revendu plus cher qu'acheté), le prélèvement s'applique dessus. Et donc tu ne repaie pas la TVA sur la création du produit, qui a déjà été versée à l'état.

    La TVA ne s'applique pas que sur les objets mais sur les services. Par exemple tu développes un logiciel, tu paies (ou ton client paie) la TVA sur cette activité. Pareil pour du commerce de neuf. Et de vieux, donc.

    Si tu as acheté ce produit en payant explicitement la TVA tu verses a priori la TVA sur le chiffre d'affaire hors taxe mais en déduisant la TVA que tu as payée. Sinon tu paies la TVA sur la différence entre le prix de vente et le prix d'achat (ce qui revient au même : c'est calé sur la valeur ajoutée).

    C'est donc juste le principe de la TVA : chaque élément de la chaîne paie la TVA sur la valeur ajoutée qu'il "produit".

  • [^] # Re: restons classique...

    Posté par  . En réponse au journal Quelles extensions pour votre Firefox?. Évalué à -1.

    Le relais DNS, que tu vas contacter directement, permet de rassembler beaucoup d'informations, non ? Plus ou moins la liste complète des sites sur lesquels tu navigues, même s'il ne reçoit pas une demande à chaque fois que tu t'y rends. Alors que la bibliothèque truc.js utilisée par plein de sites et qui est en cache, ton navigateur va la récupérer une fois puis la garder à long terme. Évidemment à la vitesse à laquelle évoluent les bibliothèques javascript ça change peut-être souvent, mais l'information doit être assez parcellaire.

  • # Remontée des travaux

    Posté par  . En réponse à la dépêche "Capitán Sévilla El remake" acquiert la langue de molière. Évalué à 1.

    J'imagine que vous distribuez vous-mêmes la version francophone parce que c'est plus facile. Avez-vous tenté/réussi de remonter vos travaux de traduction au projet d'origine ? Comment ça s'est passé si c'est le cas ?

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 1.

    Si je comprends bien, manipuler l'arbre explicitement est toujours difficile (ou pas possible dans ce modèle ?) mais ça fournit une syntaxe pour écrire des macros simples (un truc qui existe dans scheme, Racket est d'ailleurs cité dans l'article), c'est ça ? Contrairement à ppx qui fournit un outil plus complet pour manipuler l'AST mais au prix d'une plus grande complexité ?

  • [^] # Re: restons classique...

    Posté par  . En réponse au journal Quelles extensions pour votre Firefox?. Évalué à 1.

    Effectivement, Firefox le garde dans son cache (c'est un peu trompeur dans la console, il affiche toutes les requêtes ; mais en regardant dans les détails il indique que ça a bien été récupéré dans le cache).

    Merci.

  • [^] # Re: restons classique...

    Posté par  . En réponse au journal Quelles extensions pour votre Firefox?. Évalué à 4.

    Il y a aussi le problème apis.google.com : les serveurs de téléchargement de bibliothèques diverses (jquery et autres). C'est une plaie. Je suppose que Google ne se prive pas pour en tirer des informations à chaque fois qu'on visite une page faisant référence à ces fichiers (il me semble bien que l'en-tête Referer est envoyé). Et si on le bloque ça empêche certains sites de fonctionner (il manque jquery par exemple…). C'est bien pour les repérer et éventuellement leur signaler la problème, mais c'est casse-pieds.

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 1.

    Ok.

    Et je lirai la dépêche sur OCaml :) .

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 2.

    Pour le passage par valeur/référence, les paramètres des fonctions lisp sont passés par valeur, l'essentiel des valeurs étant des références (comme en java, si ça te dit quelque chose : dans les variables on a en général des références à des objets).

    Les macros reçoivent en paramètre des expressions Lisp (du code Lisp), sous forme non de texte mais d'informations structurées (l'AST, qui est un truc tout simple constitué de listes imbriquées).

    Je vais prendre un exemple et le dérouler, ce sera plus simple…

    En Lisp, if est un opérateur spécial. Il s'agit d'un des quelques opérateurs existant dans le langage, qui ne peut pas être représenté par une fonction mais pas non plus par une macro parce qu'une macro ne fait que générer du code Lisp de plus bas niveau. Donc il faut bien une conditionnelle "élémentaire" pour construire les autres. Et par exemple cond, l'équivalent d'un if/elseif/elseif/else dans d'autres langages, est une macro qui se base sur if (qui génère du code contenant des if, en remplacement du cond).

    Les if s'utilisent comme ça en général (condition puis l'expression à évaluer si la condition est réalisée puis celle à évaluer sinon) :

    (if (= x 33)
      (print "réussi")
      (print "raté"))

    Les cond s'utilisent comme ça (t signifie "vrai" : la troisième condition est toujours vérifiée ; sachant que seule la première expression vérifiée conduit à évaluer l'expression correspondante) :

    (cond
      ((= x 33)
         (print "réussi"))
      ((= x 32)
         (print "presque"))
      (t
         (print "raté")))

    Il se trouve que if est un opérateur spécial et cond une macro, qui se base sur if. Pour simplifier mon exemple je vais imaginer l'inverse : cond serait un opérateur spécial compris par le compilateur et qui ne peut pas être écrit sous forme de fonction ou de macro, il n'existerait pas de macro if et je veux créer cette dernière.

    Le but est donc d'écrire une macro if qui permettra ensuite d'écrire ce code (1) :

    (if (= x 33)
      (print "réussi")
      (print "raté"))

    et qui le transforme en ce code, qui ne contient plus que cond, supposé être connu par le compilateur (2) :

    (cond
      ((= x 33)
         (print "réussi"))
      (t
         (print "raté")))

    On veut donc écrire une macro qui prend en paramètre 3 expressions Lisp : dans mon exemple ce serait (= x 33) (une liste contenant le symbole =, le symbole x et le nombre 33), (print "réussi") (une liste contenant le symbole print et la chaîne "réussi"), (print "raté") (une liste contenant le symbole print et la chaîne "raté").

    Les paramètres sont des listes représentant l'AST de ces 3 expressions. L'analyse syntaxique est déjà passée par là, la macro ne reçoit pas en paramètre le texte des expressions mais bien les expressions structurées en mémoire. C'est à dire que la macro peut vérifier si une des expressions reçues en paramètre est une liste, un nombre, … et si c'est une liste demander le nombre d'éléments, le premier élément, … : elle peut manipuler les expressions simplement, comme n'importe quelle liste contenant des données (=> le code est passé sous forme de données).

    Le but de la macro est de renvoyer une expression Lisp sous forme d'AST (des listes imbriquées) représentant le code généré. Dans ce code (mon exemple (2) plus haut), on voit bien les listes imbriquées, chaque paire de parenthèses délimitant une liste : le code résultat est constitué de listes, il va être simple de le construire en imbriquant des listes.

    Un dernier mot sur la fonction list : il s'agit simplement d'une fonction permettant de créer une liste. (list 1 2 "coucou") crée une liste contenant 3 éléments (honteusement pas du même type ;) ).

    La version moche de la macro, qui laisse bien apparaître la manipulation des listes et montre que les macros sont des bouts de code Lisp qui génèrent du code représenté par des listes imbriquées :

    (defmacro if (condition expr1 expr2)
      (list 'cond
            (list condition
                  expr1)
            (list t
                  expr2)))

    Le code crée une liste contenant le symbole cond et deux sous-listes. La première sous-liste contient deux éléments : la condition (dans mon exemple (= x 33)) et la première expression (dans mon exemple (print "réussi")).

    Une version plus simple de la macro (l'opérateur "`" permet de construire une liste, l'opérateur "," d'insérer dedans quelque chose à évaluer ; ici simplement la valeur des paramètres : la liste ainsi construite contient le symbole cond mais la valeur du paramètre condition) :

    (defmacro if (condition expr1 expr2)
      `(cond
         (,condition
           ,expr1)
         (t
           ,expr2)))

    Est-ce que tu vois comment les macros fonctionnent ? Elles prennent en paramètre des expressions Lisp qui sont des AST sous forme de listes imbriquées et renvoient un AST sous forme de listes imbriquées, le tout au moment de la compilation. L'AST généré remplaçant le code dont la macro est la racine (dans mon exemple le code (1) est remplacé par le code (2) : le compilateur voit une expression commençant par if, appelle la macro if, remplace cette expression par le résultat de l'exécution de la macro).

    Il n'y a pas de notion d'évaluation paresseuse ou non : la macro génère simplement un bout de code Lisp destiné à remplacer l'ancien. Et ce bout de code n'est rien d'autre que du code Lisp normal. De manière générale il n'y a pas d'évaluation paresseuse en Common Lisp. Par contre effectivement il faut faire attention en écrivant les macros : ici c'est très simple mais il faut éviter d'insérer expr1 à plusieurs endroits dans le code généré, sinon l'expression sera exécutée plusieurs fois. Dans ce cas il faut générer du code qui évalue cette expression et place le résultat dans une variable puis utilise cette variable. C'est un problème plus sournois dans les macros parce qu'on a vite fait d'écrire deux fois expr1 sans s'en rendre compte et d'insérer deux fois une expression dans le code généré, ce qui peut mener à des surprises au moment de l'exécution, mais ce n'est rien d'autre que l'évaluation normale de Common Lisp d'un code dans lequel on aurait recopié deux fois la même expression.

    Par contre la macro est évaluée au moment de la compilation, donc une seule fois.

    Il reste juste à noter que cette macro est assez simple mais qu'elle pourrait faire des calculs complexes, parcourir les expressions qu'on lui passe en paramètre (il s'agit de simples listes), faire n'importe quoi pour générer le code Lisp destiné à la remplacer. Il s'agit simplement de code Lisp quelconque manipulant des listes (parcours, construction, …).

    Est-ce que c'est plus clair ?

    (Et comment vous faites pour la coloration syntaxique de Common Lisp ? J'ai mis clojure parce que je n'arrive pas à la faire marcher avec "Common Lisp" ; ça marche bizarrement d'ailleurs, parfois j'écris n'importe quoi comme langage, ou même je le supprime, et ça continue à fonctionner : j'ai supprimé le langage sur le premier extrait de code et il est coloré quand même).

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 1.

    D'accord, merci pour les précisions.

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 2.

    Effectivement je ne connaissais pas la terminologie Lisp, une macro n'est rien d'autre qu'une fonction si je comprend bien ? ou sont-ce des fonctions d'une forme particulière ?

    En pratique elles sont définies avec defmacro plutôt que defun, mais a priori derrière ça génère une fonction. À l'intérieur c'est juste du code Lisp, comme dans une fonction.

    Première différence importante : alors que pour une fonction les paramètres sont évalués puis leur valeur passée à la fonction, pour une macro les expressions sont passées telles quelles. Donc si j'écris le code :

    (truc 1 (+ 1 2))
    

    Si truc est une fonction, elle reçoit en paramètres 1 et 3, qui est le résultat de l'évaluation de l'expression (+ 1 2).
    Si truc est une macro, elle reçoit en paramètre 1 et (+ 1 2), qui est une liste contenant 3 valeurs : un symbole et deux nombres. En Lisp les symboles sont des objets manipulables, comme les fonctions, les nombres, les chaînes et autres : ils peuvent être stockés dans une variable, dans une liste, … comme n'importe quelle autre valeur.

    Deuxième différence importante : les macros renvoient une expression Lisp (une valeur simple ou une liste, cette liste représentant le code qui remplacera l'utilisation de la macro). La macro reçoit donc des paramètres et exécute du code Lisp qui génère le code qui doit la remplacer.

    Troisième différence importante : les macros sont évidemment exécutées au moment de la compilation : dans mon exemple précédent, si truc est une macro le compilateur exécute la macro en lui passant les deux expressions, récupère une nouvelle expression qui remplace celle qui se trouvait dans le code. Puis il continue son parcours (si la racine de l'expression résultat est à nouveau une macro il la développe).

    De fait la syntaxe Lisp représente directement son AST, là où en OCaml on passe par des modules du compilateur pour le manipuler. Mais il me semble que c'est essentiellement pour des raisons de typage : le Lisp est du lambda-calcul faiblement typé, là où OCaml est du lambda-calcul fortement typé statiquement.

    En fait Lisp est plutôt fortement typé, même par rapport à Java (que je connais mieux qu'OCaml). Par rapport à OCaml je ne sais pas, mais "faiblement typé" je ne pense pas. Par contre c'est typé dynamiquement, effectivement. Tout ça si on suit le découpage suivant, qui représente bien les choses je trouve : typage faible/fort, statique/dynamique, explicite/implicite. Pour Lisp c'est typage fort, dynamique et implicite, pour OCaml typage fort, statique et implicite (si j'ai bien compris, c'est implicite et on précise dans les cas où le compilateur est perdu, la plupart du temps il se débrouille pour déduire les types).

    La "syntaxe" de Lisp est une représentation assez simple de l'AST. L'intérêt de la notation préfixée c'est que les parenthèses délimitent des listes et qu'une macro n'est qu'une fonction un peu particulière qui reçoit des listes en paramètre et qui doit générer une liste (l'arbre représentant l'expression qui la remplace). Et tout ça est assez simple à manipuler avec les fonctions de base du langage.

    Pour OCaml je ne connais pas donc j'ai un peu de mal à comparer avec les outils de manipulation de l'arbre. En Lisp il faut générer l'arbre pour vérifier le code par exemple (visuellement, en l'exécutant ou avec un analyseur de code, mais pour avoir une idée du code généré il faut exécuter la macro), avec OCaml je ne sais pas si le compilateur doit générer l'arbre pour le vérifier ou s'il peut vérifier directement le code de la fonction de remplacement pour savoir si le résultat sera valide, ce qui serait une différence.

    Par curiosité, dans ton exemple en OCaml tu écris ça :

    (* je code le test if-then-else en fonctionnel pure *)
    let iff b e1 e2 = if b then e1 else e2

    Dans un langage comme Java ça ne marche pas parce que les expressions e1 et e2 seraient évaluées systématiquement avant d'être passées en paramètre à la fonction iff.
    En Common Lisp ça marche si iff est une macro, ce qui permet de ne pas évaluer systématiquement les deux expressions avant de choisir le résultat à renvoyer.
    En OCaml ça marche parce que le langage est purement fonctionnel et que le compilateur va se débrouiller pour n'évaluer que les expressions nécessaires ? Ou tu as fait un exemple simplifié ?

    Sur ce, bon week-end à tout le monde :) . Je lirai la suite (s'il y a) dimanche ou lundi sans doute.

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 1.

    Pour les AST : les listes imbriquées sont une manière de représenter des arbres, donc le code lisp forme un arbre. C'est une représentation directe de l'AST, contrairement à une syntaxe infixe. On peut avoir d'autres représentations bien sûr. Mais le fait que le code représente directement l'arbre est une caractéristique importante du langage (pour écrire les macros notamment).

    Pour le lambda-calcul : je ne connais pas tellement, je veux juste dire que personne n'écrit de vraies expressions de lambda-calcul telles quelles, c'est quand même assez violent. L'exemple fourni dans le message auquel je répondais ne ressemble en rien à du Lisp. D'ailleurs si j'en crois cette expression ou l'article de wikipédia ça n'a pas l'air d'être systématiquement enfermé dans des parenthèses : exemples de fonctions, parenthésage.

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 3.

    D'accord, donc en fait je pense que tu ne connais pas du tout Lisp… Comme je ne connais rien en OCaml c'est un peu délicat comme conversation :) .

    Je vais essayer de préciser quelques trucs, je pense que ça va simplifier.

    En Lisp tout ce qui est entre parenthèses est une liste. Donc le code source est lui même constitué de listes imbriquées : (print (+ 1 2)) est constitué d'une liste contenant le symbole "print" et une sous-liste, qui elle-même contient un symbole et deux entiers. On remarque que la notation préfixée + les imbrications de liste => on écrit directement l'AST. Contrairement à la syntaxe de la plupart des langages où on a des notations mélangées (préfixée dans le cas des fonctions, infixée dans le cas des opérateurs mathématiques par exemple), qui est traduite par l'analyseur syntaxique en un arbre, en Lisp le code représente déjà cet arbre.

    Il ne faut pas confondre les macros du C avec celles de Lisp. Les macros du C font du remplacement de texte. Les macros de Lisp sont des fonctions qui reçoivent en paramètre des expressions Lisp. Donc des atomes (comme des nombres ou des chaînes) et des listes. La représentation uniforme entre le code et les données (les listes essentiellement) permet de manipuler ça très simplement. Si je crée une macro tructruc qui s'utilise de cette manière : (tructruc 1 (bidule 2)), la macro est une bout de code Lisp (comme une fonction) qui reçoit deux paramètres : le nombre entier 1 et une liste contenant un symbole ("bidule") et le nombre entier 2. L'analyse syntaxique est déjà faite, la macro reçoit en paramètre des expressions faciles à manipuler avec les opérations standards sur les listes. Et sans outils plus ou moins complexes de compilation. Pour générer du code c'est très simple : le code n'est jamais qu'une liste contenant des éléments simples et des sous-listes, le tout représentant l'AST. De ce que je comprends de ton message, OCaml est passé d'outils de bas niveau des compilateurs (analyse syntaxique notamment, avec le préprocesseur) à des outils de plus haut niveau sur les AST, ce qui est plus simple. Et ça a l'air bien, c'est plus proche du Lisp ;) . Par contre j'ai cru comprendre que ça ne permettait de créer que des variantes des opérateurs let, fun et if. Sinon la syntaxe pour définir le nouvel AST a l'air horrible (en Lisp il suffit de construire l'arbre sous forme de listes imbriquées : dans une page présentant la fonctionnalité je vois cette phrase : "For example, Exp.tuple [Exp.constant (Const_int 1); Exp.constant (Const_int 2)] would construct the AST for (1, 2). While unwieldy, this is much better than elaborating the AST directly." ; c'est vrai, mais en lisp on aurait juste écrit '(1 2)) et ça a l'air compliqué de lire les arbres/sous-arbres de l'expression d'origine pour en tirer des informations à placer dans l'arbre transformé.

    Pour ce qui est de "défigurer" la syntaxe : en Lisp c'est facile, il n'y a "pas de syntaxe", juste les AST. C'est-à-dire qu'il n'y a rien à défigurer. En fait on peut modifier le sens de caractères (par exemple dire que si j'écris un truc entre crochets ça veut dire quelque chose de particulier) mais ce n'est pas avec les macros. Donc par exemple imaginons que je veux ouvrir un fichier et être sûr de le fermer correctement, même si une erreur est signalée, … Certains langages ont une syntaxe pour ça (c'est le cas de Lisp aussi mais on va faire comme si ce n'était pas le cas). Je crée une macro with-open-file (celle qui existe déjà en Lisp, mais on aurait pu l'écrire nous-mêmes) et j'utilise ça comme ça :

    (with-open-file (fic "/chemin/du/fichier")
      ...)
    

    La syntaxe n'est pas défigurée, la macro a la même forme que tout le reste : une expression sous forme d'une liste dont le premier élément est le nom de la macro. Comme pour une fonction en fait (voir le code avec print plus haut). Comme un bloc try-with-resources en java.

    Pareil si je veux une macro qui définit des classes ayant certaines caractéristiques : je crée une macro "def-classe" qui prend en paramètre les noms des attributs de la classe et génère tout ce que je veux (accesseurs, opérations particulières, copie des objets, … ce qui me passe par la tête). Et ça s'utilisera comme ça :

    (def-classe personne
      nom
      prenom
      date-naissance)
    

    Il n'y a rien de défiguré : ça ressemble à l'utilisation de la macro defclass de Lisp (qui permet de définir les classes).

    Défigurer la syntaxe c'est beaucoup plus facile dans les langages qui ont une syntaxe.

    Pour ce qui est du lambda-calcul : euh… oui, bon, le lambda-calcul c'est un truc un peu théorique quand même :) . Si la syntaxe de Lisp colle à quelque chose c'est aux AST. Pour échanger les valeurs de deux variables on peut écrire (rotatef x y). Pour plus je ne sais pas s'il existe une macro (rotatef les décale d'un rang, donc pour 3 ça doit aller mais au-delà c'est moins évident ; d'un autre côté utiliser une seule instruction pour permuter plein de valeurs, bon… ou alors il y a let). En cas de besoin on pourrait écrire une macro qui s'utilise comme ça par exemple :

    (swap (x y z) (z x y))
    

    Ou bien comme ça :

    (swap (x z) (y x) (z y))
    

    pour mieux voir les paires.
    On peut faire avec moins de parenthèses, mais séparer les deux listes c'est plus clair qu'écrire (swap x y z z x y).

    Rien à voir avec l'expression de lambda-calcul que tu indiques, quelle idée… :)

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 3.

    Je ne vais pas entrer dans le sujet pour ou contre les déclarations et vérifications statiques de types. Et je ne connais pas tellement OCaml, donc je dis peut-être des conneries dans ce qui suit… J'ajoute que du coup j'ai jeté un œil sur tout ça mais que le projet semble assez complexe et que lire du OCaml c'est assez rude (je comprends que c'est subjectif, mais de mon côté je ne vois pas d'"horreur du parenthésage" dans Lisp : les parenthèses disparaissent assez vite, il n'y a même pas besoin de les regarder).

    Dans mon message je faisais remarquer que créer une structure de données (html), y ajouter du code écrit dans langage complet (pas un langage créé pour l'occasion et moins complet) et les mêler simplement ça nécessite quelques dizaines de lignes de code. Je prenais un exemple très simple à réaliser en Lisp, je n'ai pas dit qu'il n'existait pas de choses plus complexes (y compris pour écrire du javascript en Lisp ou vérifier l'arbre html). Dans le lien que tu cites, la partie Eliom seule compte 30.000 lignes de code… Dans la plupart des langages de programmation il existe des outils de génération html / de sites dynamiques, ce n'est pas ce que je mettais en avant.

    Un des intérêts des macros est de permettre d'étendre la syntaxe du langage, je ne vois pas en quoi c'est un problème de conception. S'il n'y a pas de mécanisme d'extension tu peux moins écrire les choses comme tu veux. Et dans le code d'Eliom (c'est peut-être là que je n'ai pas tout compris) j'ai l'impression que des outils de compilation intégrés au langage sont utilisés. Donc pas de macros mais on utilise des outils propres aux compilateurs pour étendre la syntaxe…

    Un des bouts de code en question, mais il y en a un peu partout :

    (** Signature of specific code of a preprocessor. *)
    
    module type Pass = functor (Helpers: Helpers) -> sig
    
      open Helpers.Syntax
    
      (** How to handle "{shared{ ... }}" str_item. *)
      val shared_str_items: Ast.Loc.t -> Ast.str_item list -> Ast.str_item
    
      (** How to handle "{server{ ... }}" str_item and toplevel str_item. *)
      val server_str_items: Ast.Loc.t -> Ast.str_item list -> Ast.str_item
    
      (** How to handle "{client{ ... }}" str_item. *)
      val client_str_items: Ast.Loc.t -> Ast.str_item list -> Ast.str_item
    
      [...]
  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 1.

    Le prix (d'un point de vue langage, mettant de côté les conséquences sur la complexité du compilo), c'est que tout se ressemble, le simple et le compliqué sont difficiles à distinguer, la syntaxe n'encourage pas certaines approches par rapport à d'autres, et les idioms ont tendance à être moins prévisibles.

    Si on parle de Common Lisp, le langage se présente effectivement comme multi-paradigme, mais c'est moins le cas pour Scheme ou Clojure.

    J'aime bien cette approche assez souple mais ce qui me plaît le plus c'est vraiment la capacité à construire des couches de plus haut niveau, à finir par ne plus te demander comment faire entrer ce que tu veux exprimer dans le moule du langage mais à te demander assez librement d'un côté ce que tu veux réaliser et de l'autre comment tu veux l'écrire, Lisp te permettant presque automatiquement de faire le lien entre les deux (il n'y a pas que les macros, c'est un ensemble).

    Et effectivement il n'y a pas vraiment d'avantage pour un programme de quelques centaines de lignes : pour un programme relativement modeste tu choisis une approche et tu t'y tiens. J'aime bien Lisp quand même dans ce cas, je trouve les choses assez simples à lire/écrire, mais ce n'est clairement pas là qu'il se distingue. Je ne trouve pas gênant d'utiliser du Lisp pour un petit programme ni de lire un petit programme en Lisp (en général il n'y a pas tellement d'approches mélangées à cette échelle), mais l'avantage réel n'apparaît que pour des programmes plus importants.

    Malheureusement je pratique mais ça ne se montre pas encore, pour des raisons diverses. Et décrire comment tous les éléments de Lisp s'emboîtent pour arriver à ce résultat est assez difficile, c'est mieux avec des exemples. Je suppose que cette discussion resurgira d'elle-même quand je présenterai ici une partie de ce que je fais. J'essaierai de donner des exemples plus concrets parce que j'imagine que là ça fait un peu discussion entre gens qui savent déjà de quoi ils parlent et que pour le reste du monde c'est difficile à saisir sans avoir vraiment mis le nez dedans.

    Pour juste un petit exemple : écrire un générateur html qui permet de mêler du code Lisp et du code html (comme les jsp de java mais avec tout le langage Lisp sous la main, sans un (en fait deux dans le cas des jsp, sans compter les balises personnalisées) langages supplémentaires à apprendre) ça nécessite même pas 100 lignes de code, avec les échappements html appliqués automatiquement. Et si tu écris des applications web tu sais à quel point la sécurité de la génération des pages est difficile (sinon je te le dis ;) : ajouter du texte dans des pages dont les méta-données sont du texte c'est assez délicat parce qu'il faut faire attention partout et que par définition les humains ne sont pas très doués dans ce domaine). Étendre ce générateur pour qu'il traite tous les cas (échappement des paramètres javascript, échappement correct des url, jetons dans les urls, …) c'est quelques centaines de lignes de code. Avec une syntaxe finale qui mêle harmonieusement lisp et html (ou ce qui le représente), sans avoir rien d'autre à apprendre, y compris pour créer tes propres composants de présentation (de simples fonctions/macros Lisp). C'est un exemple où il y a peu de choses à apprendre pour savoir comment ça marche, qui libère le développeur de pas mal de problèmes (moins de choses à penser partout) et qui permet à des gens ayant une expérience modérée du développement web d'éviter les conneries. À l'échelle d'un site de 3 pages ce n'est pas intéressant mais si tu réalises des applications plus complexes c'est vite rentabilisé.

    Pour l'analyse statique on en reparle dans un peu plus longtemps :) . Mais rien ne s'oppose a priori à réaliser une analyse statique du code : ce n'est pas parce que le langage est dynamique qu'en pratique on redéfinit pendant son exécution les fonctions existantes.

  • [^] # Re: C'est bien dommage

    Posté par  . En réponse au journal C++17 est sur les rails. Évalué à 2.

    Attention, "dialecte de Lisp" désigne en général un langage de la famille Lisp (Common Lisp, souvent appelé Lisp, Scheme (dont Racket est une des implémentations/variantes), Emacs Lisp, Clojure, …).

    C'est vrai pour la création de langages basés sur Lisp, mais si tu utilises une bibliothèque de fonctions dans n'importe quel langage il faut apprendre les fonctions et le traitement qu'elles réalisent. En Lisp il y a en plus des macros et de la même manière il faut apprendre ce qu'elles font. Il s'agit juste de poser des couches d'abstraction par-dessus le langage de base.

    Et c'est vrai qu'il vaut mieux faire attention à ne pas écrire des macros pour tout et n'importe quoi, mais la contrepartie est qu'il est possible d'atteindre des niveaux d'abstraction plus élevées que dans d'autres langages. Donc de programmer dans un langage plus spécifique au domaine et en écrivant moins de choses. Et en relisant du code plus clair quand on doit relire/modifier le programme, avec moins de détails à apprendre. Avec les avantages classiques associés aux fonctions par exemple : écrire une macro c'est capturer une syntaxe, une forme qui revient dans le programme, et avoir du code généré (de manière transparente, sans le voir étalé partout) toujours de la même manière plutôt que du code de bas niveau qui se ressemble à différents endroits. Donc moins pratique pour quelqu'un qui arrive et qui veut faire une petite modification parce qu'il y a plus de choses à apprendre avant de commencer mais plus pratique pour faire des modifications à plus long terme. Et encore, si la modification est d'assez haut niveau il faut juste comprendre le langage construit sur la syntaxe de base et on peut se dispenser d'en connaître tous les détails : faire des modifications de haut niveau, même mineures, sur le code est plus commode.

    Évidemment écrire des macros qui servent deux fois dans un programme et truffer un petit programme de macros et spécificités diverses n'est pas une bonne idée. Mais si le programme est important capturer certaines formes qui n'entrent pas dans des fonctions et écrire le programme à l'aide de concepts de plus haut niveau est un gains de temps important, y compris pour le relire et comprendre ce qu'il fait ou même faire des modifications de haut niveau.

    On note que dans divers langages on voit passer l'expression "langage spécifique au domaine" (ou "domain specific language" / "DSL" parfois) mais en général on a soit une syntaxe moche soit un langage externe comme un truc à base de XML.

    Et pour les macros on peut afficher le code qu'elles génèrent, si on veut voir les détails :) .

  • [^] # Re: Incitation au troll

    Posté par  . En réponse au journal Projet de loi français El Khomri. Évalué à 1.

    Si le poste est supprimé c'est déjà un motif de licenciement autant que je sache.

  • [^] # Re: Un grand merci à AMD !

    Posté par  . En réponse au journal Vulkan 1.0. Évalué à 2.

    "conformance" existe sur le wiktionnaire en anglais seulement. Enfin le wiktionnaire francophone mais le mot est bien indiqué comme étant un mot anglais.

  • [^] # Re: J'espère que quelqu'un va foncer !

    Posté par  . En réponse au journal Mozilla s'apprête à laisser la main pour Thunderbird. Évalué à 4.

    D'un autre côté si les administrations qui l'utilisent avaient acheté le logiciel d'un éditeur ils auraient payé pour ça. Les administrations qui utilisent des logiciels libres peuvent très bien jouer le jeu et contribuer un peu aux logiciels dont elles se servent, même si ça ne coûte pas autant qu'acheter des logiciels propriétaire.

    Faire attention à mes impôts c'est bien, que l'état ne décide pas simplement de subventionner Thunderbird parce que ça a été décidé sur linuxfr je comprends, mais je n'attends pas non plus que l'État se comporte comme un prédateur (ou juste un boulet). Le logiciel libre est une économie du don (intéressé ou pas, mais si une entreprise fait une contribution intéressée et utile au reste du monde c'est quand même une forme de don), contribuer aux logiciels qu'on utilise quand on en a les moyens et que ça a bien servi c'est une forme de participation bien adaptée je trouve.

  • [^] # Re: map/fold/filter

    Posté par  . En réponse à la dépêche The Go Programming Language. Évalué à 2.

    "syntaxic sugar" ("syntactic", non ? à moins que les deux ne soient valables en anglais) -> "sucre syntaxique"

  • [^] # Re: Hacker ?

    Posté par  . En réponse au journal Hommage aux Hackers moins-connus. Évalué à 3.

    C'est plutôt méchant pour Didier Super : la chanson de Michel est juste nulle, alors que les chansons de Didier Super sont absurdes, dérangeantes. Un mélange de n'importe quoi et d'incitation à la réflexion, un glissement qui part de phrases bateaux, puis plus marquées, dans lesquelles tu le suis parce que c'est juste une chanson, on se défoule, puis une beaucoup moins acceptable d'un seul coup, qui t'arrête net. La construction est très sympa.

    Parfois (souvent ?) c'est aussi juste absurde, mais absurde bien construit et entraînant je trouve.

  • [^] # Re: Systèmes-Entités-Composants

    Posté par  . En réponse à la dépêche Je crée mon jeu vidéo E15 : J'arrête.... Évalué à 3.

    D'accord, je pense que je comprends un peu mieux les difficultés.

    Ça rejoint aussi des discussions dans les commentaires d'autres articles que tu as écrits, sur le fait que ce modèle Systèmes-Entités-Composants était plutôt un modèle de conception ou plutôt un paradigme… Quand j'ai lu des articles dessus j'ai vu ça comme un modèle de conception qui consistait à avoir des objets standards (les entités) qui accueillent des composants. Donc on assemble les objets à partir de composants. Comme alternative à la construction d'objets basés sur des classes elles-mêmes assemblées par héritage. Donc quelque chose de plutôt adapté à la représentation du modèle de données du jeu.

    Si je comprends bien tu as tenté d'aller beaucoup plus loin et de tout faire entrer dans ce modèle (ou paradigme, du coup), donc par exemple de représenter l'interface graphique sous forme d'entités et de composants aussi. D'où tes remarques sur le fait que le système d'événements n'était pas trop traité dans tes lectures. À mon avis pour que le modèle SEC soit intéressant il faut qu'il y ait pas mal de petits morceaux d'infos (des composants) assemblés de différentes manières (dans des entités). Ce qui ne correspond pas forcément à tout dans le programmation. Donc je voyais plutôt ce modèle pour les données du jeu, avec des objets plus classiques pour l'interface graphique (et sans système d'événements basé sur le modèle SEC du coup).

    Si l'idée est de gérer l'interface grâce au modèle SEC, est-ce que les entités affichées ne pourraient pas avoir un composant "affiché", qui contient leurs coordonnées sur la vue ? Comme ça savoir sur quoi on a cliqué consiste à piocher dans les entités ayant un composant "affiché" celle(s) dont la position inclut la position du clic (la position de l'entité peut inclure une notion de profondeur, pour sélectionner la bonne en cas de superposition). Du coup le système recevant les événements recherche l'entité concernée, décide de ce qui se passe et lance le traitement approprié (dans un autre système sans doute). On a ici un système qui a un rôle classique de contrôleur. Et c'est ce système de contrôle qui dit "bon, on a un clic gauche sur un ennemi, il faut sans doute l'attaquer" et qui lance le traitement approprié (qui met à jour les entités, …).

    Pour l'affichage je comprends moins bien. Pour l'optimisation, est-ce que tu as un index qui te permet de retrouver les entités affichables qui ont une coordonnée sur la carte avec x entre tant et tant et y entre tant et tant ? Pour l'histoire des composants "texte" et "mini-carte", ça pourrait être une gestion hors des entités-composants, avec des objets classiques plutôt. Ou bien des fonctions permettant d'afficher l'un ou l'autre (le composant "affiché" sert à récupérer toutes les entités à afficher, dont le texte et la mini-carte, puis ensuite on appelle une fonction d'affichage basée sur la classe exacte du composant décrivant la nature de l'élément (donc une hiérarchie de classes pour le composant décrivant la nature de l'entité à afficher)). Là c'est un peu compliqué, mais c'est parce que la représentation par des objets classiques est peut-être plus évidente qu'une représentation par des entités composées de blocs assemblables différemment. En gros je comprends qu'avoir des personnages avec des propriétés réagençables c'est intéressant, y compris pour les marquer comme affichable, affiché, … ; par contre pour des composants graphiques bof : ils ont sans doute un comportement unique et un affichage qui dépend de leur classe, et c'est tout. Donc les représenter par des composants et entités revient un peu à simuler ce système de classes par des entités-composants (par exemple le composant décrivant leur nature, avec choix la méthode de tracer en fonction de ce composant), ce qui est plus compliqué qu'autre chose (a priori, mais il y a peut-être des avantages que je ne vois pas).

    Je n'ai pas non plus bien saisi où tu plaçais tes traitements. Dans ce que j'avais compris, les entités et composants servaient surtout à représenter les données et les systèmes les traitements. Donc on a une séparation très nette données/traitements (ce qu'on ne fait pas forcément dans les jeux avec des objets habituellement). Il n'y a pas trop de problèmes de propagation entre entités parce que ce sont les systèmes qui s'occupent de ça. Et eux-mêmes manipulent des entités sans se soucier de leur classe mais plutôt de leurs composants, c'est-à-dire qu'ils traitent les entités ayant une propriété commune (mobile, ennemi, position, affichable, …), représentée par un composant de la même classe. Ce qui permet de recombiner facilement ces propriétés en les ajoutant/retirant aux entités. Du coup côté interactions ce ne serait pas plus difficile dans ce modèle que dans un jeu classique, puisque c'est fait pareil (sauf la recherche des entités concernées).

    Pour ce qui est de la difficulté à prévoir l'évolution, je pensais qu'au contraire le modèle SEC permettait d'ajouter après coup des propriétés sans avoir à rebricoler des hiérarchies de classes, et que ça simplifiait. Tant qu'on ne s'en sert que pour le modèle de données du jeu en tout cas. Et que les systèmes étaient plutôt gros. Des fonctions normales de moteur de jeu (gestion de combats, d'affichage, …) mais simplement au lieu de se baser sur des classes et des listes pour trouver les données (la liste des bâtiments du jeu par exemple), ils se basaient sur un tas d'entités indexées par composant et que ça permettait par exemple d'implémenter la phase de production du tour en cherchant toutes les entités ayant un composant de production (plutôt que parcourir la liste des bâtiments et regarder pour chacun s'il a des capacités de production), le traitement de production se faisant comme dans un jeu classique. Ce qui permet par exemple à des troupes d'avoir une capacité de production si on le décide plus tard. On pourrait refaire cet exemple avec une capacité de régénération par exemple, si c'est plus proche de ton jeu.

  • # Systèmes-Entités-Composants

    Posté par  . En réponse à la dépêche Je crée mon jeu vidéo E15 : J'arrête.... Évalué à 10. Dernière modification le 31 août 2015 à 03:53.

    Est-ce qu'il serait possible d'avoir une description plus détaillée des difficultés avec le modèle systèmes-entités-composants ? Ou du moins quelques exemples, même si tu ne reprends pas tous tes problèmes :) .

    Je voyais les systèmes un peu comme des modules, un truc assez simple : un système de combat, un système de mouvement, … Avec quelque chose pour enchaîner tout ça. Est-ce l'enchaînement qui est difficile par exemple, parce qu'on a des actions de différentes natures mêlées et que du coup on sort vite de l'exemple "je lance le système de mouvement qui fait bouger tout le monde, puis le système de combat qui fait tous les combats, puis le système de rendu…" ?

    Ou avec des systèmes plus fins (juste des fonctions permettant de traiter différents aspects des objets animés, en mouvement, …) est-ce qu'il est trop compliqué de construire des fonctions pour traiter les entités ayant tel ou tel composant plutôt que les considérer globalement ? Par exemple pour savoir comment déplacer un personnage j'ai besoin de ses infos de mouvements mais aussi assez souvent d'autres données qui sont dans un autre composant, ça ne se résumé pas à "telle fonction qui s'applique à n'importe quelle entité possédant ce composant" ?

  • [^] # Re:

    Posté par  . En réponse à la dépêche Lettre ouverte de Mozilla au CEO de Microsoft. Évalué à 9.

    Une source sur cette information et sur le fonctionnement de ce truc ?

    Autant que je me souvienne, la vérification des sites fonctionne avec une liste téléchargée périodiquement (donc pas d'envoi à chaque requête) et chez Mozilla (?), non ?