Je suis toujours ravi de supprimer de code. C'est ça de moins à maintenir :)
La programmation c'est l'art d'ajouter des bugs à un fichier texte vide.
Moins de code, moins de bugs, moins de travail, plus de temps pour les choses vraiment importante.
Pour ce qui est de Rust, je note le troll (c'est permis, on est trolldi). Cependant certains bouts de code ont déjà commencé à être porté. Je ne pense pas qu'on verra de si tôt un noyau Linux entièrement en Rust, mais ce langage a déjà commencé à s'y introduire :
Oui, cela montre que les développeurs ont vraiment à coeur les utilisateurs.
Par contre, je pense pas qu'ils l'ont fait pour "un" utilisateur, mais qu'ils ont utilisé cet utilisateur spécifiquement comme exemple que on ne sait jamais quel est l'impact, car il y a probablement tout les utilisateurs qui ne lisent pas la mailing list ou les nouveautés.
Comme le nommage de variable est clair, on comprend tout de suite qu'on veut dormir des secondes carrées non ?
Le soucis, c'est la définition de time.Second (1 million de nanoseconde).
Avec un système d'unité, on obtiendrait effectivement s² et générerait une erreur de compilation car time.Sleep attend des secondes.
Ici à la place, on a delay * 1 million * 1 million. Une erreur qui passe inaperçue surtout si l'assignation de delay est loin de son utilisation. Bonjour les galères de debug.
La création de ces constantes part d'une bonne intention, mais comme d'habitude avec Golang, c'est juste un footgun de plus.
L’homogénéité des formules, le travail de normalisation et l’estimation de la propagation des erreurs sont trop complexes pour être gérés par un langage de programmation.
On disait pareil des techniques pour vérifier la sécurité des opérations de manipulation de la mémoire avant que Rust arrive.
Après, Letlang n'est pas un langage scientifique, donc je ne compte pas forcément introduire des techniques pour le calcul de précision (propagation d'erreur etc…).
Cela dit, la notion d'unité et de quantité reste un outil fort pratique :
auto-documentation des données manipulées (on ne mélange pas les torchons et les serviettes, encore faut-il savoir faire la différence)
vérification de la cohérence des opérations (j'ai dit, on mélange pas les torchons et les serviettes, maintenant qu'on sait faire la différence…)
conversion explicite (c'est fini de confondre degrés et radians quand on manipule cos/sin/tan, ce qui arrive souvent en gamedev)
Bien que imprécise, cette notion est quand même pratique. Par exemple :
implémente moi un programme qui lance cette touche tout les 2 mois
mets moi un rappel de cet événement dans 5 mois
entraîne ce réseau neuronal pendant 1 mois complet
On a ainsi :
une règle de récurrence, solution : donne moi le jour du mois au tu veux l'exécuter
une date, solution : j'incrémente uniquement la partie "mois" de la date initiale
une durée, solution : exprime cette durée dans une unité plus précise
L'idée c'est de fournir un framework cohérent pour exprimer précisément cette notion imprécise. Sujet drôlement complexe. C'est pourquoi je proposais dans l'article de différentier :
durée "absolue" en secondes
fenêtre temporelle à l'aide de 2 points temporels
Ainsi, on pourrait construire à partir d'un point temporel "1 mois" en fonction du calendrier associé à ce point temporel.
Je ne connais pas de langage qui gère le calendrier dans le langage. Ça fait plutôt parti de la bibliothèque standard.
C'est pour ça que j'ai dit :
Revenons au sujet. Quand je vais devoir écrire la bibliothèque standard du langage. Quel serait selon toi le moyen le plus correct d'écrire cet objet timedelta ? Quelle est son unité ?
Concrètement, je trouve la manière de faire de Python pas bonne. Celle de Javascript est encore pire. Passons sur le Go qui est très douteux sur le sujet aussi.
La question ici, c'est vraiment : à quoi ressemblerai un framework correct pour manipuler des dates et des durées calendaires ?
Sauf que je peux déjà plus ou moins le faire sans Generics ça.
typeComparableinterface{Compare(otherComparable)(int,error)}typeFoostruct{}func(Foo)Compare(otherComparable)(int,error){switchother.(type){caseFoo:// do stuffreturn0,nildefault:return0,errors.New("wrong type")}funcSort(items[]Comparable)([]Comparable,error){// do stuff}
Alors oui, ça fait un peu de boilerplate. Mais c'est possible.
Donc je persiste et signe, les generics servent surtout a faire de la composition d'interface justement pour retirer le boilerplate de ces fonctions.
Si t'as rien qui catch ton exception, ça remonte aussi en haut de la stack et fini par quitter le programme anormalement.
Je disais que le panic/recovery était plus moche car au moins avec de vrai exceptions tu peux contrôler précisément ou et quand le recovery code s'exécute.
Quand tu lis la documentation d'une fonction, si elle retourne un Result, tu peux tout de suite savoir les cas d'échec possibles. Et le système de type du langage peut vérifier que tout les cas sont gérés.
C'est pas le cas avec les exceptions. Les throws que tu fais ne font pas partie de la signature de la fonction.
Les exceptions sont une forme de early return, souvent comparé à goto. Pour ma part je trouve les 2 concepts complémentaire, cf Elixir ou on utilise {:ok, val} ou {:error, reason} pour ce qui est prévisible et raise / rescue pour ce qui ne l'est pas.
Dans certains cas je peux considérer qu'une requête HTTP qui retourne une 404 est prévisible mais qu'un network unreachable ne l'est pas : est-ce que la ressource existe ?
Dans d'autres cas, je considère que toute erreur est imprévisible : j'ai besoin de tel document
Dans le premier cas, si je reçois un {:error, 404} je peux retourner false et laisser l'exception network unreachable se propager.
Dans le second cas je transforme le {:error, reason} en exception (unwrap).
Les Result et les exceptions permettent tout deux de séparer le code et la gestion d'erreur, mais la sémantique, les performances, et l'intégration au système de type sont radicalement différent.
map : Result<T, E> -> Result<U, E> avec f : T -> U
map_err : Result<T, E> -> Result<T, E2> avec f : E -> E2
and_then : Result<T, E> -> Result<U, E2> avec f : T -> Result<U, E2>
or_else : Result<T, E> -> Result<U, E2> avec f : E -> Result<U, E2>
…
Le principe est de te permettre, grâce à ce type et ses opérations, de composer des "computations" et d'en récupérer un type final cohérent que tu peux traiter correctement.
[^] # Re: Nom par défaut gcc/clang
Posté par David Delassus (site web personnel) . En réponse au journal [LWN] Une porte de sortie pour a.out. Évalué à 7.
Cargo (Rust) et Go utilisent le nom du projet (dossier dans lequel il y a le Cargo.toml ou go.mod).
Quelque chose de similaire serait sympa non ?
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Intérêt
Posté par David Delassus (site web personnel) . En réponse au journal [LWN] Une porte de sortie pour a.out. Évalué à 7.
Je suis toujours ravi de supprimer de code. C'est ça de moins à maintenir :)
La programmation c'est l'art d'ajouter des bugs à un fichier texte vide.
Moins de code, moins de bugs, moins de travail, plus de temps pour les choses vraiment importante.
Pour ce qui est de Rust, je note le troll (c'est permis, on est trolldi). Cependant certains bouts de code ont déjà commencé à être porté. Je ne pense pas qu'on verra de si tôt un noyau Linux entièrement en Rust, mais ce langage a déjà commencé à s'y introduire :
Pour continuer dans la tradition du trolldi, à quand GNU/Hurd en Rust du coup ?
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Intérêt
Posté par David Delassus (site web personnel) . En réponse au journal [LWN] Une porte de sortie pour a.out. Évalué à 6.
Développeurs heureux = kernel mieux maintenu
kernel mieux maintenu = utilisateur heureux
Moins de code c'est aussi un vecteur d'attaque réduit, donc une sécurité accrue.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# Coquille
Posté par David Delassus (site web personnel) . En réponse au journal [LWN] Une porte de sortie pour a.out. Évalué à 7. Dernière modification le 24 mars 2022 à 23:57.
Si un(e) modo passe par là, j'ai écorché le nom de l'auteur : Jonathan Corbet
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Linux, meilleur support à long terme
Posté par David Delassus (site web personnel) . En réponse au journal [LWN] Une porte de sortie pour a.out. Évalué à 10.
Oui, cela montre que les développeurs ont vraiment à coeur les utilisateurs.
Par contre, je pense pas qu'ils l'ont fait pour "un" utilisateur, mais qu'ils ont utilisé cet utilisateur spécifiquement comme exemple que on ne sait jamais quel est l'impact, car il y a probablement tout les utilisateurs qui ne lisent pas la mailing list ou les nouveautés.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# Discussion sur HackerNews
Posté par David Delassus (site web personnel) . En réponse au journal [LWN] Une porte de sortie pour a.out. Évalué à 7.
https://news.ycombinator.com/item?id=30792059
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Fun fact: Golang c'est simple, simplement débile
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Faire la différence entre un nombre et une quantité. Évalué à 2.
Le soucis, c'est la définition de
time.Second
(1 million de nanoseconde).Avec un système d'unité, on obtiendrait effectivement s² et générerait une erreur de compilation car
time.Sleep
attend des secondes.Ici à la place, on a
delay * 1 million * 1 million
. Une erreur qui passe inaperçue surtout si l'assignation de delay est loin de son utilisation. Bonjour les galères de debug.La création de ces constantes part d'une bonne intention, mais comme d'habitude avec Golang, c'est juste un footgun de plus.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Angle mort des langages de programmation
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Faire la différence entre un nombre et une quantité. Évalué à 2.
On disait pareil des techniques pour vérifier la sécurité des opérations de manipulation de la mémoire avant que Rust arrive.
Après, Letlang n'est pas un langage scientifique, donc je ne compte pas forcément introduire des techniques pour le calcul de précision (propagation d'erreur etc…).
Cela dit, la notion d'unité et de quantité reste un outil fort pratique :
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Le mois physique
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Faire la différence entre un nombre et une quantité. Évalué à 2. Dernière modification le 22 mars 2022 à 10:54.
Oui, c'est bien un problème problématique ;)
Bien que imprécise, cette notion est quand même pratique. Par exemple :
On a ainsi :
L'idée c'est de fournir un framework cohérent pour exprimer précisément cette notion imprécise. Sujet drôlement complexe. C'est pourquoi je proposais dans l'article de différentier :
Ainsi, on pourrait construire à partir d'un point temporel "1 mois" en fonction du calendrier associé à ce point temporel.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Calendrier
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Faire la différence entre un nombre et une quantité. Évalué à 2.
C'est pour ça que j'ai dit :
Concrètement, je trouve la manière de faire de Python pas bonne. Celle de Javascript est encore pire. Passons sur le Go qui est très douteux sur le sujet aussi.
La question ici, c'est vraiment : à quoi ressemblerai un framework correct pour manipuler des dates et des durées calendaires ?
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
# Fun fact: Golang c'est simple, simplement débile
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Faire la différence entre un nombre et une quantité. Évalué à 2.
https://cs.opensource.google/go/go/+/refs/tags/go1.18:src/time/time.go;l=607
J'espère que tu as le temps.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Kamoulox !
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 4.
Totalement d'accord. Et c'est aussi plus complexe à implémenter correctement dans un interpréteur / compilateur.
C'est la méthode Erlang/Elixir. Mais ça génère pas trop de boilerplate grâce au pattern matching.
C'est plus ou moins la méthode de Rust avec le
?
que tu mets après les appels de fonction qui retournent cette structure.https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Déjà évoqué...
Posté par David Delassus (site web personnel) . En réponse au lien Le dev du paquet NPM "node-ipc" le sabote pour condamner l'invasion de l'Ukraine. Évalué à 6.
C'est marrant car la majeur partie des commentaires de ce lien se plaigne justement du lien en question :P
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Kamoulox !
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 2. Dernière modification le 17 mars 2022 à 23:32.
Premièrement, c'est pas le sujet, le concept de checked exception existe, qu'elles soient utilisées ou non en pratique est un autre débat.
Deuxièmement, c'est principalement les
RuntimeException
(et classes filles) qui sont unchecked.https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Conteneurs
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 3.
Sauf que je peux déjà plus ou moins le faire sans Generics ça.
Alors oui, ça fait un peu de boilerplate. Mais c'est possible.
Donc je persiste et signe, les generics servent surtout a faire de la composition d'interface justement pour retirer le boilerplate de ces fonctions.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Kamoulox !
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 3.
C'est justement pour ça qu'il précise juste après l'existance des exceptions "unchecked".
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Deepfake, pas fake
Posté par David Delassus (site web personnel) . En réponse au lien First ever war deepfake. Congratulations. Évalué à 6.
Ah le porno… Moteur de l'innovation depuis toujours.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Kamoulox !
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 5.
Pas sûr de comprendre.
Si t'as rien qui catch ton exception, ça remonte aussi en haut de la stack et fini par quitter le programme anormalement.
Je disais que le panic/recovery était plus moche car au moins avec de vrai exceptions tu peux contrôler précisément ou et quand le recovery code s'exécute.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Kamoulox !
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 4. Dernière modification le 17 mars 2022 à 15:05.
Sauf que tu as
recover()
en Go pour "catch" le panic.Ce qui veut dire que panic/recover c'est le try/catch de Go, mais en plus moche.
https://go.dev/blog/defer-panic-and-recover
EDIT: A moins que c'est justement ce qui tu voulais dire, auquel cas, ignore mon message.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Kamoulox !
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 5.
Quand tu lis la documentation d'une fonction, si elle retourne un Result, tu peux tout de suite savoir les cas d'échec possibles. Et le système de type du langage peut vérifier que tout les cas sont gérés.
C'est pas le cas avec les exceptions. Les throws que tu fais ne font pas partie de la signature de la fonction.
Les exceptions sont une forme de early return, souvent comparé à goto. Pour ma part je trouve les 2 concepts complémentaire, cf Elixir ou on utilise
{:ok, val}
ou{:error, reason}
pour ce qui est prévisible etraise
/rescue
pour ce qui ne l'est pas.Dans certains cas je peux considérer qu'une requête HTTP qui retourne une 404 est prévisible mais qu'un network unreachable ne l'est pas : est-ce que la ressource existe ?
Dans d'autres cas, je considère que toute erreur est imprévisible : j'ai besoin de tel document
Dans le premier cas, si je reçois un
{:error, 404}
je peux retournerfalse
et laisser l'exception network unreachable se propager.Dans le second cas je transforme le
{:error, reason}
en exception (unwrap).Les Result et les exceptions permettent tout deux de séparer le code et la gestion d'erreur, mais la sémantique, les performances, et l'intégration au système de type sont radicalement différent.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Go ou golang ?
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 8.
Le nom c'est Go.
Mais quand je fais des recherches google, les résultats sont plus pertinents en utilisant le terme "golang". Du coup je mélange un peu les deux.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Kamoulox !
Posté par David Delassus (site web personnel) . En réponse au journal Golang, oops you did it again. Évalué à 10.
L'avantage du type
Result<Data, Error>
c'est les opérations que tu peux chaîner.Result<T, E> -> Result<U, E> -> Result<V, E> -> ...
Tu peux donc découpler la gestion d'erreur de ton algorithme et ce sans avoir besoin d'exception et de "jump" dans le code.
Un exemple en Elixir avec ma lib rustic_result :
En gros :
map : Result<T, E> -> Result<U, E>
avecf : T -> U
map_err : Result<T, E> -> Result<T, E2>
avecf : E -> E2
and_then : Result<T, E> -> Result<U, E2>
avecf : T -> Result<U, E2>
or_else : Result<T, E> -> Result<U, E2>
avecf : E -> Result<U, E2>
Le principe est de te permettre, grâce à ce type et ses opérations, de composer des "computations" et d'en récupérer un type final cohérent que tu peux traiter correctement.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: ouf
Posté par David Delassus (site web personnel) . En réponse au journal [Letlang] Écrire un compilateur en Rust (partie 2). Évalué à 2.
Miam, merci de ne pas avoir fait un journal pour ça :D
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # 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é à 2.
Ah je pensais que tu parlais du lien dans la partie 1 vers la partie 2.
Le lien dans la partie 2 vers la partie 1 et cité tout en haut de l'article :)
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg
[^] # Re: Mastermind
Posté par David Delassus (site web personnel) . En réponse au lien Clone de Wordle pour les ouvertures d'Échecs. Évalué à 4.
Wordle c'est aussi un mastermind du dictionnaire anglais.
-- Venec, Kaamelott.
https://link-society.com - https://kubirds.com - https://github.com/link-society/flowg