Nous avons le plaisir de vous présenter le deuxième numéro de l'année de « Nitération », la lettre d’information du projet Nit.
Les statistiques combinées pour le mois de février 2015 donnent:
$ git diff --shortstat v0.7.1..v0.7.2
587 files changed, 9396 insertions(+), 4472 deletions(-)
$ git log --first-parent v0.7.1..v0.7.2 | grep 'Pull-Request: #' | wc -l
40
Ont contribué (ou ont eu des patchs intégrés): Jean Privat, Alexandre Terrasa, Alexis Laferrière et Lucas Bajolet
Grâce à la bibliothèques d'accès à l'API de Github, un service de ludification du développement de Nit est proposé sous le nom denitrpg.
Le service est accessible en ligne http://nitlanguage.org/rpg/games/privat/nit
Il fonctionne en traquant les événements émis par github (hooks) et attribue des points (nitcoins) en fonction des contributions des joueurs telles que proposer des commits ou relire des pull-requests.
Le logiciel est en cours de développement, des fonctionnalités supplémentaires sont attendues avec impatience par les joueurs.
Un userscript est même disponible pour interfacer directement nitrpg depuis github.
La TODO list des constructeurs est bientôt complétée.
Il est maintenant possible de (re-)définir l'ordre des initialiseurs du constructeur d'une classe.
Bien que rarement nécessaire (par design des nouveaux constructeurs), cela est utile dans trois cas : en cas de conflit d'initialiseurs, pour ordonner des initiateurs, ou pour désactiver/réactiver des initialiseurs dans des sous-classes spécifiques.
Cela se fait par l'annotation de classe autoinit (on réutilise ainsi la même annotation que pour marquer les méthodes comme initialiseurs) suivi de la liste des initialiseurs.
class A
var a: Int
var b: String
end
class B
super A
var c: Bool
autoinit c, b, a
end
var a = new A(10, "foo")
var b = new B(true, "foo", 10)
Pour vider la liste des initialiseurs, il faut utiliser l'annotation noautoinit sans argument (choix qui a été préféré à un autoinitsans argument).
class C
super B
noautoinit
end
var c = new C
print c.b # BOOM! `b` pas initialisé
Indépendamment noautoinit est devenu synonyme de noinit sur les attributs, le nouveau nom est plus clair et no(auto)initsur les attributs est sémantiquement l'opposé de autoinit sur les méthodes.
class D
var s: String is noautoinit
end
var d = new D
print d.s # BOOM! `s` pas initialisé
autoinit to explicitly list initializers. 31ade8fNotez que, comme dans les exemples précédents, les annotations de classe peuvent enfin être placées où l'on veut dans la classe. Un effet de bord est que cela devient également vrai pour la clause super, ce que plusieurs identifient comme pratique car cela permettrait de regrouper les propriétés par super-classes, en cas d'héritage multiple, pour aider la lecture.
cachedcached sur les méthodes fut l'une des premières annotations à voir le jour, toutefois elle était fragile et posait des problèmes de compréhension au programmeur débutant. L'annotation lazy sur les attributs, apparue plus tard, a été recommandée en replacement car elle est implémentée de façon robuste et plus simple à comprendre.
L'annotation cached a enfin disparue et les quelques cas qui restaient ont été trivialement convertis vers lazy.
Le travail pour offrir des API de qualité sous Android continue.
Générer du C standard plutôt que générer du code machine pour les différentes architectures matérielles a comme avantage la portabilité, c'est pourquoi le support de 4 architectures Android est maintenant en place.
Ce mois-ci, on observe plusieurs améliorations intéressantes de la bibliothèque standard en terme de robustesse, performance et élégance de l'API.
Suivant l'exemple des Map du mois dernier, c'est au tour des Set d'accepter null comme élément. Rien de fondamental mais c'est plus élégant.
Le service Map::get_or_null a été optimisé dans les HashMap et, tant qu'à faire, utilisé là où cela semblait pertinent. L'intérêt du service est double : il est plus rapide qu'un has_key suivi d'un [] et il évite au programmeur de répéter la valeur du map et celle de la clé.
Les types virtuels de string, dont l'objectif est de maintenir une symétrie entre les services de String et ceux de Buffer, ont été figés ce qui permet d'éviter les erreurs de redéfinitions qui brisent l'API. Le comportement des services dans Buffer reste toutefois peu intuitif, du travail de design reste encore à faire.
Moins de fuites mémoire dans les services de String.
Les noms des classes de la hiérarchie des flots, tels que IFStream, faisaient l'unanimité contre eux. C'est pourquoi, la plupart ont été renommées avec des identifiants que l'on espère plus KISS et POLA.
Ainsi, les classes de base sont nommées Reader pour les flots d'entrée, Writer pour les flots de sortie et Duplex pour les flots d'entrée-sortie ; la superclasse commune s'appelle Stream et ne contient (pour l'instant?) que les services de fermeture (close) et d'interrogation d'erreur (last_error). Les sous-classes spécifiques suivent un schéma régulier tel que FileReader,FileWriter, FileDuplex et FileStream.
La classe Streamable a été renommée en Writable qui représente mieux l'idée d'un objet qui peut être écrit (efficacement) dans un fichier (write_to_file), sous forme de chaîne (write_to_string) ou refilé à un Writer qui saura en faire quelque chose (write_to).
Le plugin Vim a été amélioré au niveau de l'auto-complètement.
D'une part les modules importés sont scannés ce qui améliore le complètement de base (ctrl-P). D'autre part, un omnifunc (ctrl-x ctrl-o) a été développé pour Nit ce qui permet un complètement plus syntaxique/sémantique et affiche la documentation des entités suggérées.
Sous la pression populaire, le compilateur primitif résidant dans c_src a été régénéré.
L'ancien a servi pendant 3 mois, le précédent 3 mois aussi, et celui d'avant 4 mois. On note une certaine régularité, rendez-vous dans quelques mois pour voir si cela se confirme.
Une nouveauté cette fois, le compilateur primitif ne dépend plus de libunwind ce qui permet de boostrapper manuellement sur les architectures ne disposant pas de la bibliothèque comme le Raspberry Pi.
Le make initial en profite également pour compiler les outils avec l'option --semi-global. Cela allonge un petit peu la durée dumake mais produit des binaires plus efficaces. Les utilisateurs devraient y gagner au final.
Le loader sait chercher les projets dans le path des bibliothèques de Nit. Cela permet, par exemple, à la commande nitls standard de lister les modules de la bibliothèque standard sans avoir besoin de lister le chemin exact. Cette fonctionnalité est utilisée par le plugin Vim pour nourrir l'auto-complètement.
--logL'option --log fournie par les outils était utilisée par l'ancien compilateur nitc mais a été oubliée dans la conversion vers le nouveau compilateur. Cet oubli a été en partie réparé et les outils commencent maintenant à produire divers fichiers d'information si on leur demande gentiment.
L'outil d'analyse des cas d'utilisation de la covariance a été nettoyé et intégré à nitmetrics. L'interprétation des résultats reste toutefois à refaire sur le nouveau code.
Les chiffres bruts, sans analyse, sont disponibles grâce à Jenkins pour qui ça intéresse (cherchez Detection of the usage of covariance static type conformance dans le fichier).
Le compilateur séparé gagne --substitute-monomorph, une nouvelle optimisation globale à l'édition de liens (inspirée de ce que faisait le vénérable PRM). L'idée est de remplacer les appel polymorphes via VFT de la compilation séparée classique par un appel direct à un symbole.
Ainsi, au lieu de coder l'appel de méthode par
(RECV->VFT[COLOR])(ARGS)
on a plutôt
SYMBOL(ARGS)
Lors de l'édition de liens, une analyse globale est effectuée : si l'appel est monomorphe, le symbole est résolu directement vers la méthode cible ; sinon le symbole est résolu vers une courte fonction (appelée trampoline) qui effectue un appel polymorphe traditionnel via VFT.
Au final, et par rapport au comportement par défaut du compilateur séparé, les appels monomorphes sont optimisés (appel direct, vs. appel via VFT) mais les appels polymorphes sont plus lents (appel du trampoline en plus de l'appel via VFT). Le pari est que le gain sur les appels monomorphes compense la perte sur les appels polymorphes.
Pour l'instant, les évaluations préliminaires ne montrent pas un gain spectaculaire. Toutefois l'application du monomorphisme est améliorable car actuellement elle se fait au niveau de la propriété globale et non au niveau du site d'appel. En effet, actuellement un seul symbole est utilisé par propriété globale, donc la substitution vers le monomorphisme se fait seulement si tous les sites d'appels de cette propriété globale sont monomorphes.
Enfin, une nouvelle option --link-boost active toutes les optimisations globales à l'édition de liens (c'est-à-dire celle présenté ci-dessus ainsi que --colors-are-symbols introduite précédemment)
Une implémentation alternative (option --call-gard) évite l'utilisation d'un trampoline mais utilise une garde sur le symbole et inline l'appel via VFT si la garde échoue.
if SYMBOL != null then
SYMBOL(ARGS)
else
(RECV->VFT[COLOR])(ARGS)
end
On a un coût systématique supplémentaire à cause du test mais un call (un jump en fait) de moins si la garde échoue. Les résultats montrent que la garde est bien pire (jusqu'à 10% de perte) que l'approche originale qui est de faire des appels systématique via VFT.
Dans les fichiers C générés, les chemins des fichiers utilisés pour afficher les erreurs dynamiques (tels que cast et assert échoués) ne sont plus des littéraux mais des variables globales. Cela à l'avantage d'alléger les fichiers C mais surtout de les rendre plus indépendants du répertoire de compilation.
En effet, les chemins des fichiers sont la plupart du temps relatifs donc dépendent du répertoire de compilation ce qui n'est pas optimal dans un contexte de compilation indépendante des modules. Maintenant, la plupart des fichiers C produits ne dépendent que du module compilé et non plus du programme client ou du répertoire de travail.
De plus, l'outil ccache est capable de réutiliser les produits de compilation même provenant de répertoire de compilation distincts. Ceci accélère le temps de recompilation même quand plusieurs répertoires .nit_compile sont utilisés.
nitdoc a été fortement refactorisé et différents modules créés en fonction des différentes préoccupations de l'outil d'auto-documentation.
De plus, le framework développé permet de manipuler les éléments de documentation indépendamment de leur rendu ce qui augmente la modularité de l'outils et permettra à terme un développement plus simple.
Ce travail s'est fait sans modification fondamentale du HTML généré. On attend donc la suite.
ASTDump and ANode::dump_tree 48bbbbc