Nous avons le plaisir de vous présenter le onzième numéro de « Nitération », la lettre d’information du projet Nit.
Les statistiques combinées pour le mois d'octobre donnent:
$ git diff --shortstat v0.6.9..v0.6.10
451 files changed, 16531 insertions(+), 3653 deletions(-)
$ git log --first-parent v0.6.9..v0.6.10 | grep 'Pull-Request: #' | wc -l
47
Ont contribué (ou ont eu des patchs intégrés): Jean Privat, Alexis Laferrière, Lucas Bajolet, Jean-Christophe Beaupré.
Encore une barrière psychologique de tombée : plus de 500 PR ont été acceptées dans le dépôt principal.
Nit est syntaxiquement proche du langage de script Ruby, qui est lui-même proche de Perl qui est lui-même proche des outils systèmes shells, sed et awk.
En particulier, le shebang d'indication d'interpréteur fonctionne depuis longtemps et quelques-uns utilisent Nit pour leurs scripts de tous les jours.
#!/usr/bin/env nit
print "Hello World!"
Afin d'améliorer la scriptabilité du langage, l'interpréteur accepte désormais des options habituels des interpréteurs de scripts Unix.0d4de25
L'option -e permet d’interpréter un programme directement passé en argument.
$ nit -e 'print 5+5'
10
L'option -n permet d'itérer sur chaque ligne de l'entrée. Dans le programme, la ligne s’appelle sys.line au lieu de $_ en Perl ou Ruby mais c'est à peu près la seule différence.
$ echo "hello world" | nit -n -e 'print sys.line.capitalized'
Hello World
Là où cela devient intéressant est que l'option -n est implémentée directement dans la bibliothèque (niti_runtime.nit) grâce au raffinement des services de base, et non en dur dans l'interpréteur.
L'option --define (ou -D) a également été introduite dans l'interpréteur et le compilateur. Cette option permet de raffiner des méthodes directement dans la ligne de commande. Cela permet de fixer certains paramètres et comportements lors de la compilation sans avoir à créer de bottom-module quasi-vides. ff3bde9
$ nitg foo.nit -D prefix=/opt/nit/
Grace au typage statique, l'existence de la méthode désignée par -D et sa signature sont vérifiées, ce qui rend l'usage de l'option robuste. D'ailleurs, la valeur de l'option est interprétée en fonction du type de retour de la méthode. Actuellement, seul String, Int et Bool sont acceptés mais cela devrait représenter la grande majorité des cas d'utilisations.
module foo
fun str: String do return "test"
fun num: Int do return 1
fun flag: Bool do return false
print str
print num
print flag
$ nitg foo.nit
$ ./foo
test
1
false
$ nitg foo.nit -D str=hello -D num=42 -D flag
$ ./foo
hello
42
true
Comment distribuer des programmes Nit ? Sur de nombreux systèmes, comme Android, distribuer un programme compilé ne pose pas de problème. Dans le monde UNIX, l'hétérogénéité des architectures fait qu'il est souvent plus simple de distribuer le code source.
Or, aussi incroyable que cela puisse sembler, Nit n'est pas disponible sur tous les ordinateurs.
La solution de rechange consiste alors à distribuer le code C qui sert déjà de langage intermédiaire dans notre chaîne de compilation. C'est ce qui est fait dans le répertoire c_src du projet qui contient de quoi bootstrapper les outils mais qui est en réalité issu du code C d'une compilation précédente et nettoyé (cf. le script mkcsrc).
L'idée est de généraliser l'approche pour permettre de produire du code C autonome et distribuable à partir de n'importe quel compilation. Ce qui permet alors de distribuer directement le répertoire de compilation. 98e5400
Avec les bonnes options, un le compilateur Nit peut produire un répertoire de compilation distribuable tel quel.
$ nitg examples/hello_world.nit --semi-global --no-cc --dir hello --compile-dir hello
--semi-global pour réduire la taille du code C et optimiser un peu--no-cc pour ne pas lancer la compilation du C--dir hello pour placer le futur binaire dans le répertoire hello--compile-dir hello pour placer les fichiers C également dans helloEnsuite, le diffuseur distribue le répertoire hello (dans un tarball par exemple). L'utilisateur final n'a alors qu'à décompresser et lancer le make pour avoir son exécutable.
$ cd toto
$ make
[...]
$ ./hello_world
Hello, World!
Les fonctions variadiques (varargs) acceptent maintenant qu'on leur donnent un tableau déjà constitué (reverse-vararg). 5121228
Afin d'éviter d'éventuelles ambiguïtés, une syntaxe particulière avec une ellipse est utilisée.
fun foo(a: Int...) do print a.join(":")
foo(1,2,3) # => "1:2:3"
var a = [4,5,6]
foo(a...) # => "4:5:6"
La PR en profite également pour nettoyer et simplifier la façon dont les varargs sont gérées par les moteurs.
Les attributs acceptent une syntaxe additionnelle, proche de celle de méthodes, pour leur valeur initiale. 070e1b0
class A
var toto: String do
var res = "hello"
res += ", world!"
return res
end
end
Cela est surtout utile dans le cas des attributs lazy dont la valeur est calculée seulement au premier accès (et non lors de l’instanciation).
class B
var toto: String = ""
var tata: String is lazy do
var t = toto
if t == "" then return "Hello!"
return "Hello, {t}!"
end
end
var b = new B
print b.tata # => "Hello!"
var b2 = new B
b2.toto = "World"
print b2.tata # => "Hello, World!"
Pour rappel, l'annotation autoinit permet d'indiquer que certaines méthodes doivent être invoquées automatiquement pendant la phase des initialiseurs lors de la construction.
L'annotation a été étendue aux attributs pour indiquer que la valeur initiale doit être également évaluée pendant la phase des initialiseurs, et non au début de l’instanciation comme cela est fait par défaut. afceecb
L’intérêt de retarder l'évaluation de la valeur initiale apparaît lorsque la valeur dépend d'autres initialiseurs.
class A
var toto: String
var tata: String = toto + ", World!" is autoinit
end
var a = new A("Hello")
print a.tata # => "Hello, World!"
Sans le autoinit, le new A aurait échoué car au moment de l'initialisation de tata, toto aurait été non-initialisé.
Alternativement, le programmeur aurait pu choisir l'annotation lazy, voire noinit et effectuer l'affectation lui-même (dans le initpar exemple).
Au final, l’intérêt de l'annotation reste douteux mais l'implémentation fut triviale et un bon prétexte pour nettoyer le code. On verra si les gens l'utilisent...
new-factoryLes fabriques new, introduites pour la FFI puis utilisées pour certaines classes internes, ont été généralisées. e71e1df
Les méthodes introduites par le mot clé new (à la place de fun ou init) sont définies dans des classes mais se comportent comme des méthodes top-level (statiques). Elle servent à retournent des instances construites à la main.
L’intérêt est de pouvoir court-circuiter le mécanisme d’instanciation normal via une sorte de sucre syntaxique.
Cela permet aussi de fournir des pseudo-constructeurs aux interfaces et classes abstraites qui peuvent choisir parmi leurs sous-classes laquelle est la plus intéressante à instancier réellement.
Cela permet au final d'encapsuler davantage de détails, à la grande joie des concepteurs d'API.
abstract class Personne
new(age: Int) do
if age >= 18 then
return new Adulte(age)
else
return new Enfant(age)
end
end
end
Toujours dans les constructeurs, la page de la manuel qui les concerne a commencé à être réécrite.
Rien n'est codé encore, mais une excellente discussion sur la bonne syntaxe à utiliser s'est déroulé sur github.
Le problème semble ne pas avoir de solution parfaite. Il faut donc réussir à trouver la meilleure solution imparfaite.
Nouvelle bibliothèque pthreads de manipulation des threads POSIX en Nit. 35d9538
Elle permet de créer de façon simple des threads, des mutex et des barrières. Le programmeur est toutefois responsable de la validité et de la cohérence de ses programmes car les bibliothèques de Nit ne sont pas thread safe.
Pour limiter le problème, deux façons de gérer des collections synchronisées sont offertes : une par spécialisation (proxy) et une par raffinement.
Toutefois, l'absence volontaire de variable globale dans le langage limite généralement les problèmes de synchronisation aux objets que le programmeur partage volontairement entre plusieurs threads.
Afin de s'inter-connecter avec les technologies des années 2000, Nit acquiert enfin un parseur XML. Et pas des moindres vu qu'il s'agit d'un parseur SAX, subtilement nommé saxophonit. cdd10a3
La classe Comparator et ses sous-classes laissent tomber leurs paramètres formels au profit d'un type virtuel. 6a72930
Cela permet de résoudre les problèmes de contravariance et rend au final le code plus lisible et plus robuste qu'il ne l'était avant.
Un nouveau service finish a été introduit dans les itérateurs. b2e361b
Il permet aux boucles for d'informer l'itérateur que le travail est terminé (par exemple parce-qu'il a été interrompu par un break) ce qui permet à l'itérateur de libérer d'éventuelles ressources.
Nouveau module push-back reader qui propose des flots en lecture avec remise. C'est toujours utile. 04f4deb
Ajout de la fonction Int::bin_not dans lib/math. 4b62a1a
Le module console gagne une nouvelle API plus robuste pour les couleurs. 0146538
Nettoyage du répertoire examples. De nombreux fichiers sont déplacés dans un sous-répertoire de leur bibliothèques respective. Cela donne le sentiment que les choses sont mieux rangées. d65a790
Un nouveau programme, opportunity, propose une alternative aux doodle et framadate de ce monde. 323e292, c591913 et8894e31.
Du travail reste à faire mais c'est une nouvelle preuve de concept de programme complet en Nit. Les technologies Nit utilisées sont les bibliothèques nitcorn (serveur web), sqlite3 (base de données) et template (patrons de pages).
Le service est publiquement accessible (quand il n'est pas en maintenance).
Les tests de régression de Nit ne sont pas des blagues : plus de 4h sur notre serveur jenkins qui teste des milliers de programmes les uns à la suite des autres.
D'où l'idée de tester les programmes en parallèle pour gagner du temps.
Le nouveau programme nitester utilise la bibliothèque Nit openmpi pour distribuer les tests sur les noeuds d'un cluster.
Pour le cluster turing de l'UQAM, quelques 9000 tests se déroulent en moins de 3 minutes si l'on répartit les taches sur les 120 processeurs disponibles. C'est impressionnant vu que plus de 2h sont nécessaires si un seul processeur est utilisé.
Il reste encore un peu de travail de finition pour profiter de cette nouvelle infrastructure directement dans les jobs du serveur d'intégration.
Quoi de mieux qu'un interpréteur brainfuck pour valider l'expressivité d'un langage? 4d482e6
Plein de choses en fait...
Un nouveau warning détecte les comparaisons inutiles à null. 894c39e
Les outils gagnent des pages de manuel. Pour l'instant il n'y a pas grand chose d’intéressant mais cela devrait s'améliorer avec un peu d'effort. d7a953d
Le débogueur devient plus robuste et amical. Peut-être un jour il sera même rapide... 8ab2093
Un bug dans nitlight a été identifié et contourné. Le service http://nitlanguage.org/code/ est maintenant rétabli. dcf6b2f
Le projet Rosetta Code propose de répertorier, pour plus de 700 taches, les meilleurs implémentations naturelles dans plus de500 langages de programmation.
Pour le langage Nit, tenter de résoudre ces tâches est un bon exercice de mesure de l'expressivité du langage.
C'est aussi de la programmation facile à donner à réaliser à un débutant en Nit, ou à un expert désœuvré.
Enfin, c'est un bon moyen de documentation du langage par l'exemple.
Une première brique a été posé par la réalisation de 12 premières taches. a97e7e7
Du nettoyage de code (c'est toujours bien). e43a2bf et 2e2b3f3
De l’extension de grammaire pour préparer les fabrique new, les retours multiples et les attributs initialisés avec un bloc. (voir au dessus.) e1e9193
transform sait enfin transformer les boucles complexes (while et for) en des boucles plus simples (loop). Cela permettra de simplifier les moteurs voire d'ajouter un jour des phases d'optimisation de haut niveau. 380d220
Le compilateur primitif c_src a été regénéré. La dernière génération datait de fin juillet. Cela permettra à la bibliothèque standard et aux outils de profiter des nouveautés du langage de ces trois derniers mois, en particulier les nouveaux constructeurs. 84a38b0
--dir.. e527858join_path to handle paths ending with a slash.. db10c01MAttributeDef.static_type in the graph.. 50e4753intro methods. db8e46cJsonArray. 54be77b