lundi 30 décembre 2013

Voir ses e-mails système dans Thunderbird

Le bon vieux "You've got mail" dans la console apporte rarement grand chose d'intéressant, du moins pour un utilisateur desktop comme moi. Cependant, cela heurtait mon TOC de savoir tous ces e-mails qui s'accumulaient dans l'horrible interface texte. Est-il possible de voir (et gérer!) ses messages dans Thunderbird? La réponse, heureusement, est oui. C'est un petit peu cochon, mais ça marche.

  • Tout d'abord, dans Thunderbird, créer un répertoire, par exemple "System", dans "Local Folders"
  • Quitter Thunderbird. Aller dans le répertoire correspondant à votre profil, par exemple
    cd .mozilla-thunderbird/xxxxxxxx.default/Mail/Local\ Folders/
    ou,
    cd .icedove/xxxxxxxx.default/Mail/Local\ Folders/
    si vous êtes un débianneux.
  • Virez le répertoire System, et remplacez le par un lien symbolique vers votre répertoire de courrier dans /var/mail:
    rm System; ln -s ln -s /var/mail/moncompte System
  • Redémarrez Thunderbird, votre répertoire System contient votre courrier! Magique, non?

dimanche 29 décembre 2013

Plus d'Infinity

J'ai fait un peu de rangement dans mes bookmarks: cliquer, vérifier que le lien existe encore (d'abord!), et vérifier que le lien m'intéresse toujours (ensuite). Énormément de liens morts, malheureusement, sur des projets dont je suivait l'actualité et qui ont disparu. Les temps changent, les gens passent à autre chose.

Quelque chose qui est toujours là, en revanche, c'est le bon vieux Infinity : Quest for Earth, dont je parlais en 2011 (ce qui ne nous rajeunit pas). Un nouveau site, quelques posts sur leur blog, et au final pas grand chose de neuf. Une nouvelle vidéo montre les capacités du moteur à afficher des terrains rocheux. Les montagnes et les champs de pierre sont tout à fait impressionnants, mais après tout ce temps, on a envie de dire, qu'est-ce qu'il y a d'autre? J'imagine que beaucoup de travail se passe en arrière plan, sur le moteur de jeu, en particulier, mais l'on reste sur sa faim. Peut-être une indication que le moteur ne remue pas autant les foules que prévu, le studio revient sur l'idée de faire un jeu avec le moteur, "Infinity : Battlescape", une sorte de pré-chauffe pour l'extrêmement ambitieux "Infinity : Quest for Earth" des débuts, centré sur le combat spacial, et financé via Kickstarter. Mhh!

lundi 2 décembre 2013

Combien est-ce qu'il y a d'utilisateurs d'Emacs dans le monde?

C'est une question que l'on se pose parfois. Quelqu'un a demandé sur StackOverflow, quelqu'un d'autre sur la mailing list, les réponses vont de 1 à 4 millions. Suivons une méthode un poil différente.

Tout d'abord, je vais partir du principe que la majorité des utilisateurs d'Emacs l'ont installé sur au moins une machine Linux. Ceci étant posé, quelle est la proportion des utilisateurs de Linux qui utilisent Emacs? De nos jours, bien peu d'utilisateurs installent du logiciel autrement que par leur gestionnaire de paquets. L'on peut donc utiliser les "popularity contests" pour découvrir la proportion d'installations sur ces distributions.

  • Chez Debian 31421 / 161281, c'est à dire environ 19%
  • Chez Ubuntu, 312120 / 2628854, c'est à dire environ 11%, ce qui est compatible avec l'idée qu'on se fait d'une démographie moins technique et plus "casual".

La page Wikipédia sur la taille de la communauté Linux parle d'environ 29 millions d'utilisateurs sur machines de bureau (je laisse volontairement de côté les utilisateurs d'Emacs sur tablette, faut vraiment en vouloir). Ramené à nos chiffres plus haut, cela donne entre 3 et 5.5 million d'utilisateurs, ce qui est étrangement proche de la première estimation sur la mailing list. On ne doit pas être loin!

lundi 25 novembre 2013

Vaadin

Je code un petit peu en Vaadin, ces jours-ci. C'est un framework Web Java, qui fournit une abstraction de très haut niveau, orientée widgets, pour écrire des applications web "riches", comme on dit. Jetez un coup d'oeil à leur démo, c'est tout à fait étonnant. Derrière, dans le code, pas une once de HTML, et à peine un poil de javascript pour spécialiser quelques affichages. L'on peut donc tout écrire en Java, avec ses callbacks sur les différents événements GUI, et le framework génère HTML + Javascript + Jason pour faire tourner le tout. Notons tout de même qu'il faudra se plonger jusqu'au cou dans les CSS si l'on veut faire quelque chose qui s'éloigne du style de base.

Comme beaucoup de frameworks de ce type, tout se passe bien tant que l'on reste dans le moule, mais l'on doit se battre un peu lorsque l'on veut adapter certains comportements. En particulier, l'écriture de nouveaux widgets semble complexe.

Alors, bien sûr, il a fallu que je tâte un peu du Java (il ne faut pas dire "Fontaine, je ne boirai pas de ton eau"), et j'apprécie fortement les classes anonymes pour écrire ses callbacks. C'est presque aussi bien qu'un lambda :)

mercredi 13 novembre 2013

wxWidgets 3.0 est sorti!

La version 3.0 de l'excellente bibliothèque graphique wxWidgets est enfin sortie, avec passage à GTK3, et quelques nouveautés comme les rubans et un Unicode simplifié. Pour plus de détails, vous pouvez vous reporter à la dépèche sur DLFP

Contrairement à QT, qui garde son préprocesseur MOC (et qui est la principale raison pour laquelle je ne l'utilise pas *), wxWidgets se dirige de plus en plus vers le C++ standard, avec notamment une meilleure intégration de la STL. Récemment, Vadim Zeitlin, un des développeurs principaux du toolkit, a posté un article tout à fait intéressant sur le blog de wxWidgets, où il montre comment combiner les dernières fonctionnalités de C++11 avec le framework. En particulier, l'ancien style de callbacks qui passait par des macros est maintenant avantageusement remplacé par un appel à la méthode Bind de chaque widget, dans lequel on peut coller un lambda, permettant un code plus dense aux fonctionnalités plus localisées.

* Un petit mot sur cette remarque trollogène: je veux bien croire que sur le principe, l'usage du pré-processeur ait un grand nombre d'avantages. C'est juste que dans mon cas d'utilisation, je cherche quelque chose qui s'intègre mieux à mon système de build pré-existant. Notons au passage que le support d'Android et iOS par les dernières versions de QT pourrait bien me faire changer d'avis.

jeudi 24 octobre 2013

Les jeux qui m'ont marqué - Dungeon Master

Ah, le bon vieux Dungeon Master! Sorti sur Atari, ce fut un hit qui lança un genre à lui tout seul. Comme les Doom-like et les Warcraft-like, il y eut (et il y a, voyez la série des Diablo) les Dungeon Master-like.

Le principe: vous montez une équipe de 4 personnages à choisir parmi une vingtaine, et parcourez un donjon en tous sens pour y basher des créatures et récupérer un artefact puissant qui sauvera le monde. Là où Dungeon Master s'est démarqué de ses prédécesseurs, c'est dans la représentation 3D du donjon, et le jeu en temps réel. Pour ajouter à l'ambiance, les éclairages sont dynamiques (il faut récupérer des torches, ou apprendre à en créer des magiques), les seuls bruits sont ceux des monstres qui s'approchent, et le décor, quoi que répétitif, est vite angoissant.

En plus des monstres à dégommer, il faudra résoudre des énigmes de plus en plus complexes mettant en jeu des trappes, des clés, des passages secrets, des téléporteurs, augmenter l'expérience de ses personnages, et trouver de l'équipement.

Ajoutons que les 13 niveaux du jeux sont de véritables labyrinthes. Il m'a fallu cartographier les niveaux petit à petit, sur des doubles feuilles à grand carreaux, notant les monstres, les mécanismes divers... Sans compter que pendant que l'on note les détails de la carte, nos personnages ont faim et soif. Il faudra donc s'y prendre à plusieurs fois, tellement il est facile de perdre en tombant dans une trappe, en tombant à court d'eau, ou tout bêtement en ayant pas trouvé suffisamment d'équipement pour terrasser les monstres de plus en plus puissants.

Le système de magie était également novateur, avec un système de runes à invoquer. L'on trouve des parchemins contenant des formules, mais il est possible de deviner certains sorts: ainsi, "feu" fait apparaître une torche magique, mais "feu" puis "aile" envoie une boule de feu.

C'est probablement un de mes premiers flips vidéo-ludiques: tourner au coin d'un couloir glauque, se retrouver nez à nez avec une sorte de lézard avec des dents à la place du cou, repartir en courant dans l'autre sens, se perdre et se retrouver dans un cul-de-sac avec la bestiole qui s'approche... Ça marque! Et je dois avouer n'avoir jamais réussi à aller plus loin que le 4ème ou 5ème niveau, mon niveau d'anglais plus que limité à l'époque n'aidant pas à résoudre les énigmes ou à comprendre les sorts. Mais Dungeon Master reste le mètre étalon du genre: choix de personnages charismatiques, gestion de la nourriture et du sommeil, sorts avancés, équipements complexes, expérience gagnée au fur et à mesure dans les classes de prêtre, sorcier, combattant et ninja, niveaux tentaculaires, et tout cela sur une disquette de 720 ko!

vendredi 18 octobre 2013

Les jeux qui m'ont marqué - Another World

Développé par Éric Chahi, légende du jeu vidéo s'il en est, Another World est en (très) gros Prince of Persia chez les aliens. S'il possède la même vue de côté, la même fluidité de mouvements, il s'en démarque en revanche par une action plus variée entrecoupée de cinématiques en polygones, et bien entendu d'un univers complètement original.

Le gameplay est complètement old-school. Voyons à quoi ressemble le début de partie. Après une cinématique expliquant comment vous vous êtes fait transporter dans cet "autre monde", vous apparaissez dans une sorte de piscine glauque. Des algues apparaissent du bas de l'écran, vous attrapent. Fin de partie. Vous recommencez dans la piscine. Tentez les contrôles. Ah, on peut monter! Vous sortez de la piscine.

À gauche, un ravin. À droite, quelques ruines, d'où tombent des sortes de sangsues. L'une d'elle passe à proximité, et vous mord. Fin de partie, retour dans la piscine. Vous sortez, évitez les sangsues, et vous retrouvez nez à nez avec une sorte de sanglier furieux qui vous démolit. Fin de partie, retour dans la piscine. Retour devant le sanglier, vous repartez dans l'autre sens, ratez votre saut pour éviter les sangsues. Fin de partie, retour dans la piscine.

L'on meurt donc beaucoup, mais l'on progresse assez vite. De plus, l'action est vraiment variée, entre sauts, combats avec un pistolet à 3 modes (tir normal, bouclier, tir chargé) et énigmes. L'on se fera un allié d'un des autochtones, que l'on retrouvera à plusieurs moments de l'aventure.

L'on retrouve beaucoup de points de design qui ont depuis fait leur chemin, mais à l'époque étaient très novateurs: cinématiques non seulement au début, mais également au milieu de l'action, interface minimaliste sans barre de vie ni autres compteurs pour une meilleure immersion, l'exploration d'un monde cohérent et mystérieux... Another World m'avait complètement scotché, et me scotche encore.

mardi 8 octobre 2013

Generalized attributes

Quelles autres surprises g++4.8 nous réserve dans sa besace? Eh bien, une nouvelle fonctionnalité de C++11 est la gestion des attributes généralisés. L'idée est de permettre de spécifier un comportement via des directives, certaines standard, d'autres spécifiques au compilateur. La syntaxe est plutôt ésotérique: autant définir un attribut est trivial, puisqu'il s'installe [[entre double crochets]], autant le placement de l'attribut en lui même est moins évident puisqu'il va indiquer s'il s'applique à un type ou à une instance. Je vous renvoie aux exemples pour les détails sordides, intéressons nous plutôt aux attributs qui sont dès maintenant disponibles

Le premier de ces attributs est [[noreturn]], qui permet d'indiquer que la fonction ne retournera jamais (elle peut en revanche lancer une exception). Par exemple:

void runForEver [[noreturn]] ()
{
  while(1);
}

int main()
{
  runForEver();
  
  return 0;
}

L'utilité d'un tel attribut est de permettre au compilateur d'optimiser un pareil cas, en ne générant pas le code qui gère le retour de la fonction. D'ailleurs, si jamais vous vous amusiez à faire une fonction qui retourne bien qu'ayant l'attribut [[noreturn]], le verdict serait sans appel: d'abord un warning

attributes.cpp: In function ‘void runForEver()’:
attributes.cpp:3:1: warning: ‘noreturn’ function does return [enabled by default]
 }
 ^

Et ensuite, avec g++ tout du moins, un beau crash lorsque vous faites tourner le programme. Par contre, vous êtes tout à fait autorisés, comme indiqué précédemment, à lancer une exception:

#include <stdexcept>

void countToTen [[noreturn]] ()
{
  for(size_t i = 0; i < 10; ++i);
  throw std::runtime_error("End of the road");
}

int main()
{
  countToTen();
  
  return 0;
}

Les deux autres attributs sont [[final]] et [[align]]. L'attribut [[final]] sur une méthode virtuelle permet d'empêcher la redéfinition de cette méthode dans une classe fille, et sur une classe permet d'empêcher sa dérivation. Ces fonctionnalités sont déjà fournies par les explicit virtual overrides, décrits ici. Quant à l'attribut [[align]], il permet de définir l'alignement des données, ce qui est une fonctionnalité déjà fournie par une autre spécification. Comme d'habitude, le C++ fournit beaucoup trop de manières différentes de faire la même chose... Mais c'est pour ça qu'on l'aime?

jeudi 3 octobre 2013

thread_local

Voyons maintenant une autre fonctionnalité C++11 ajoutée dans g++ 4.8, longtemps attendue par les aficionados, et complètement ignorée par les autres: thread_local. Ce mot-clé s'ajoute devant une variable globale, variable statique, ou variable de classe statique, et indique que cette variable sera locale au thread, c'est à dire que chaque thread aura accès à son bout de mémoire propre. Prenons un exemple bête pour illustrer cela. Voici un programme qui fait tourner 4 threads, lesquels incrémentent une variable miaou, puis l'impriment. L'affichage est protégé par un mutex, mais pas l'accès à la variable. Puis, lorsque tous les threads sont complets, l'on affiche le résultat.

#include <thread>
#include <mutex>
#include <iostream>

std::mutex mutex;

int miaou = 0;

void run()
{
  for(size_t i = 0; i < 1000000; ++i) ++miaou;
  std::lock_guard<std::mutex> lock(mutex);
  std::cout << miaou << std::endl;
}

int main()
{
  std::thread t1(&run);
  std::thread t2(&run);
  std::thread t3(&run);
  std::thread t4(&run);
  t1.join();
  t2.join();
  t3.join();
  t4.join();
  std::cout << miaou << std::endl;
  return 0;
}

Ayant fait tourner le programme, l'on obtient un résultat de ce type:

1164088
1177191
1229070
1222696
1222696

Les threads se sont battus pour la variable, et son évolution est donc plutôt ésotérique. Maintenant, passons miaou comme étant thread_local:

#include <thread>
#include <mutex>
#include <iostream>

std::mutex mutex;

thread_local int miaou = 0;

void run()
{
  for(size_t i = 0; i < 1000000; ++i) ++miaou;
  std::lock_guard<std::mutex> lock(mutex);
  std::cout << miaou << std::endl;
}

int main()
{
  std::thread t1(&run);
  std::thread t2(&run);
  std::thread t3(&run);
  std::thread t4(&run);
  t1.join();
  t2.join();
  t3.join();
  t4.join();
  std::cout << miaou << std::endl;
  return 0;
}

Le résultat, cette fois-ci, est complètement déterministe:

1000000
1000000
1000000
1000000
0

Chaque thread a obtenu sa propre variable miaou, et l'a incrémenté jusqu'à 1000000. Le thread principal a également obtenu sa variable, et n'en a rien fait, sa valeur est donc 0.

Bien entendu, mon exemple est complètement artificiel. Quels pourraient donc être les utilisations de la fonctionnalité?

Gérer une mémoïsation thread safe, par exemple, peut être fait en utilisant une variable statique thread_local. Voyons donc le bon vieil exemple de Fibonacci mémoïsé:

#include <unordered_map>
#include <iostream>

size_t fib(size_t n)
{
  if(n <= 2)
    return 1;
  
  static std::unordered_map<size_t, size_t> memo;
  auto result = memo.insert(std::make_pair(n, 0));
  if(!result.second)
  {
    return result.first->second;
  }
  else
  {
    return (result.first->second = (fib(n - 1) + fib(n - 2)));
  }
}

int main()
{
  for(size_t i = 1; i <= 50; ++i)
  {
    std::cout << fib(i) << std::endl;
  }

  return 0;
}

Voilà un petit programme qui affichera les 50 premiers nombres de Fibonacci, transformant l'algorithme récursif usuel à complexité exponentielle en un algorithme à complexité linéaire (on laissera de côté l'algorithme linéaire sans mémoïsation, ainsi que l'algorithme logarithmique dont on parlera peut-être un autre jour). Rien que pour rigoler, enlevez la mémoïsation, et admirez votre CPU en train de souffrir.

Tout va bien jusque là? Alors voyons ce qu'il se passe lorsque vous avez plusieurs threads accédant à la même fonction.

#include <thread>
#include <mutex>
#include <unordered_map>
#include <iostream>

size_t fib(size_t n)
{
  if(n <= 2)
    return 1;
  
  static std::unordered_map<size_t, size_t> memo;
  auto result = memo.insert(std::make_pair(n, 0));
  if(!result.second)
  {
    return result.first->second;
  }
  else
  {
    return (result.first->second = (fib(n - 1) + fib(n - 2)));
  }
}

std::mutex mutex;

void run()
{
  for(size_t i = 1; i <= 50; ++i)
  {
    size_t f = fib(i);
    std::lock_guard<std::mutex> lock(mutex);
    std::cout << i <<  " " << f << std::endl;
  }  
}

int main()
{
  std::thread t1(&run);
  std::thread t2(&run);
  std::thread t3(&run);
  std::thread t4(&run);
  std::thread t5(&run);
  std::thread t6(&run);
  std::thread t7(&run);
  std::thread t8(&run);
  t1.join();
  t2.join();
  t3.join();
  t4.join();
  t5.join();
  t6.join();
  t7.join();
  t8.join();
  
  return 0;
}

Le résultat est bien entendu indéfini, et en effet, en faisant tourner quelques fois, l'on obtient le cas où un thread accède à la map avant qu'elle ne soit mis à jour, et l'on obtient par exemple fib(50) = 2971215073 au lieu de 12586269025. Passez donc la map statique comme étant thread_local, comme ceci:

size_t fib(size_t n)
{
  if(n <= 2)
    return 1;
  
  thread_local static std::unordered_map<size_t, size_t> memo;
  auto result = memo.insert(std::make_pair(n, 0));
  if(!result.second)
  {
    return result.first->second;
  }
  else
  {
    return (result.first->second = (fib(n - 1) + fib(n - 2)));
  }
}

Maintenant, chaque thread a son propre cache, quel que soit le nombre de threads et le moment auquel ils ont été créés. L'on pourrait bien sûr partager le cache, au prix d'un mutex. Il est donc parfois plus efficace de donner son cache à chaque thread, ce qui est trivial avec le nouveau mot-clé.

Une autre utilisation possible pourrait être dans des routines de log, par exemple, chaque thread stocke les messages localement, et c'est uniquement lorsque le nombre de messages dépasse un certain seuil qu'un mutex global est pris et les messages envoyés vers l'écran ou dans un fichier. Ou encore, une fonction ayant besoin d'un buffer dynamique pourrait le déclarer en statique afin d'éviter une allocation si l'appel suivant n'a pas besoin d'un buffer plus grand, et être thread safe avec un buffer thread_local. Il n'y a plus qu'à essayer!

mercredi 2 octobre 2013

Inheriting Constructors

Avec g++4.8 qui vient de débarquer dans Debian Jessy, c'est l'occasion de se pencher sur les nouveautés C++11 de cette version du compilateur. On a vraiment l'impression que l'on racle les tiroirs du standard, parce qu'il ne manquait quand même pas grand chose. Cependant, une fonctionnalité intéressante débarquant dans 4.8 est la possibilité d'hériter un constructeur.

L'idée est qu'il est fréquent que les constructeurs d'une classe fille se contentent de passer leurs arguments à la classe mère. Dans ce cas, pourquoi s'embêter à re-déclarer le constructeur? En utilisant le mot-clé using, l'on peut donc tirer le constructeur dans la classe fille. Voyons donc un exemple.

#include 
#include 

class A
{
public:
  A(std::string a):
    _a(std::move(a))
  {
  }
  
private:
  std::string _a;
};

class B : public A
{
public:
  B(std::string b):
    A(std::move(b))
  {
  }
};

int main()
{
  B b("abc");
}

Rien de bien compliqué. Notez tout de même l'utilisation du passage par valeur du paramètre et du std::move, qui optimisent le cas où la valeur peut être déplacée. Eh bien, avec l'héritage de constructeurs, B devient simplement:

class B : public A
{
  using A::A;
};

Et ça marche exactement de la même manière. L'on imagine bien qu'avec un constructeur de classe de base prenant de nombreux paramètres, c'est beaucoup de code que l'on peut ainsi économiser.

Si A a plusieurs constructeurs, ils sont tous hérités (sauf le constructeur par copie et le constructeur par défaut, qui suivent les règles habituelles). Il est cependant possible de redéfinir un constructeur dans B avec la même signature, qui sera prioritaire sur les constructeurs hérités.

lundi 30 septembre 2013

Auto

Enfin, mon premier accrochage sur le mot-clé auto! Je sentais bien venir le truc qu'on allait me reprocher mon enthousiasme à l'utiliser.

Ma première utilisation n'avait gêné personne:

auto it = _collection.begin();
auto end = _collection.end();
for(; it != end; ++it)
{
   ...
}

Ne pas avoir à écrire des types à ralonge genre std::map<int, std::shared_ptr<Item> >::const_iterator est vraiment pratique, et rend l'utilisation d'itérateurs presque agréable (pas autant qu'un bon range-based for...).

Ma deuxième utilisation était à peine plus contestable:

auto item = std::make_shared<Item>();

Là, le type est extrêmement clair puisqu'il est indiqué à droite de l'expression. Ce serait plutôt écrire std::shared_ptr<Item> item = std::make_shared<Item>() qui serait redondant!

Par contre, ma troisième utilisation concernait le type de retour un peu compliqué d'une fonction.

auto items = getItemCollection();

Là, ça bloquait... Je trouve bien plus pratique de coller un type auto ici. Mon type est complexe et peut changer. Si je me contente d'itérer sur mes items, je peux changer mon type de retour d'un vecteur à une liste ou un set sans avoir à changer le code appelant. Mais manifestement, c'était pousser le bouchon un peu loin!

J'en appelais à de plus hautes autorités, et envoyais le lien vers le Almost Always Auto d'Herb Sutter. Je crois avoir gagné la première manche, mais ce n'est que partie remise.

samedi 21 septembre 2013

Un réveil

Rien de bien compliqué dans ce réveil. Il y avait probablement moyen d'automatiser complètement la génération des marques sur le cadran, mais je ne me suis pas foulé et ai tout fait à la mimine.

Et une autre upgrade de Postgresql sur Debian

Une fois de plus, la mise à jour de Postgres sur Debian se fait avec une facilité déconcertante.

pg_dropcluster --stop 9.3 main
pg_upgradecluster 9.1 main
pg_dropcluster 9.1 main

pgAdmin se plaint que la version de Postgresql est trop récente, mais semble fonctionner quand même.

jeudi 19 septembre 2013

Un carnet

Une nouvelle icône, représentant un carnet. Rien de bien compliqué: quelques tores pour les anneaux, deux blocs pour le papier et le fond cartonné.

Cependant, les trous pour les anneaux m'ont laissé perplexe pendant un petit moment. J'ai commencé par essayer de les modéliser en subdivisant un côté de mon cube, et en extrudant les "bons bouts", mais reconnecter l'ensemble de l'autre côté semblait un peu complexe. Finalement, l'utilisation des fonctions booléennes a donné de meilleurs résultats: j'ai simplement créé un cube traversant le carnet au niveau de l'anneau, et utilisé le modificateur booléen "différence". Les vertex du carnet deviennent un peu n'importe quoi, mais cela ne gène pas le rendu. L'essayer c'est l'adopter!

jeudi 12 septembre 2013

Going Native 2013 - Bjarne et les ramasse-miettes

Les vidéos de la conférence "Going Native 2013", grosse conférence sur le C++ réunissant, entre autres, Bjarne Stroustrup (inventeur du C++), Herb Sutter (gourou C++ devant l'éternel, bossant ces temps ci chez Microsoft, et auteur d'un excellent blog sur le C++), Andrei Alexandrescu (le roi des templates, son bouquin "Modern C++ Design" est une perle) et Scott Meyers (De la série "Effective C++", "Effective STL", "More effective C++"...), sont maintenant en ligne. Les interventions ne sont pas aussi denses que je l'aurais souhaité, mais cela m'allait très bien puisque je me les suis gardées en tâche de fond, casque sur les oreilles, pendant que je codais autre chose, revenant parfois à l'image pour regarder une diapositive.

Un point qui m'a particulièrement interpellé dans l'intervention de Bjarne Stroustrup est son avis sur les ramasse-miettes (garbage collectors ou GC en anglais). Pour autant qu'il n'en nie pas l'utilité dans certains cas, en l'occurence des bases de code vieilles, complexes, et où les responsabilités ne sont pas bien définies, il demeure cependant convaincu de la supériorité des approches RAII, pour leur déterminisme d'une part, mais aussi pour leur capacité à gérer d'autres ressources que la seule mémoire d'autre part, comme les fichiers ou les verrous sur sections critiques.

De mon côté, autant j'apprécie la présence du GC dans du Java ou dans de l'OCaml, autant ce n'est absolument pas le paradigme C++ (Bjarne indique également qu'il déteste de mot "paradigme"...), et je suis fort satisfait des pointeurs intelligents fournis par le nouveau standard (ou par Boost pour ceux qui utilisent encore le même compilo que le roi Hérode).

jeudi 5 septembre 2013

Dwarf Fortress

Je suis en train de regarder la série sur Dwarf Fortress de VanguardOfValor sur Youtube, et je suis très impressionné par le jeu.

Pour ceux qui ne connaissent pas, il s'agit d'un jeu indépendant développé par deux frangins dans lequel le joueur dirige un groupe de nains dans la construction de leur forteresse souterraine. Au fur et à mesure de son expansion, la forteresse attirera de plus en plus de colons, mais également de plus en plus de convoitises. De plus, creuser trop profond peut faire surgir des hordes de créatures démoniaques...

La complexité est tout à fait remarquable, les nains ont des dizaines et des dizaines de compétences à développer, il y a des dizaines de types de chambres et de bâtiments, et le jeu devient de plus en plus difficile au fur et à mesure que vos nains sont de plus en plus exigeants et les ennemis de plus en plus nombreux.

Chaque créature du jeu a son histoire, ses préférences, son équipement... Et il y a toujours quelque chose à faire dans sa forteresse, comme de chasser les vampires qui se sont introduits parmi les colons, répondre aux demandes des nains "nobles", permettre aux nains qui sont pris d'une obsession de construire ce qu'ils veulent, sinon ils deviennent fous ou se laissent mourir...

Graphiquement, c'est particulièrement moche, et encore, des groupes de passionnés fournissent des outils supplémentaires et des jeux de sprites pour améliorer les graphismes en ascii art. Mais qu'est-ce que ça a l'air prenant! C'est d'ailleurs la raison pour laquelle je ne me lance surtout pas à y jouer moi même :)

mercredi 31 juillet 2013

Le Carnet De Bébé

Voilà, l'application Android pour laquelle je modélisais des épingles à nourrice et des gouttes sous Blender dans le but de fournir des icônes a été publiée dans le Play Store. Il s'agit d'une application de suivi des repas (et des couches) de bébé, orienté vers les femmes qui allaitent. Et en français, s'il vous plait (il y a également la localisation en anglais et en chinois). Voici une capture qui montre mes icônes:

Empressez-vous donc d'aller la télécharger, et si vous n'allaitez pas, vous pourrez au moins admirer mon épingle à nourrice.

vendredi 26 juillet 2013

La tablette Vivaldi bouge encore

Un sursaut inespéré de la très attendue (tout du moins par moi) tablette Vivaldi, qui se veut basée sur KDE, mais surtout complètement libre.

En effet, un des développeurs, Aaron Seigo, a annoncé que les développeurs du projet allaient recevoir une pré-version de la tablette pour certification. Il y encore donc un bon bout de chemin avant que vous et moi puissions les manipuler de nos petits doigts fébriles, mais c'est un grand pas en avant.

lundi 8 juillet 2013

Les dangers de la move semantics

Voyez donc cette question que je pose sur Stackoverflow: en écrivant mes constructeurs dans le style moderne, passage des arguments copiés par valeur et déplacement, je me suis rendu compte qu'il était extrêmement facile d'utiliser par erreur la valeur déplacée dans le corps du constructeur. Comme les commentateurs du post l'ont noté, il n'existe pas vraiment de parade à ce problème, il faut juste faire très attention à ce qu'on fait...

Ce genre de bug va se multiplier, j'imagine, et sera probablement particulièrement difficile à débugger: l'on peut imaginer, dépendant de l'implémentation de chaque type, que l'on verra parfois l'ancienne valeur, parfois une valeur non initialisée, et parfois de beaux crashs. Pas de quoi jeter bébé avec l'eau du bain, mais il faudra ouvrir l’œil (comme si l'on avait déjà pas assez à penser lorsque l'on code en C++...).

mardi 4 juin 2013

Et moi qui ne poste plus...

Si ce n'est pas une honte!

Pourtant, il s'en passe, des choses. Ainsi, je viens de convaincre mon employeur de passer à C++11 et à Postgresql. Ne manque plus que de le convaincre de me laisser faire quelques heures de Blender ici et là, mais ça, c'est pas pour demain!

Ça a fait drôle a mes collègues quand je leur ai expliqué qu'il ne fallait plus utiliser "new", mais std::make_shared, comme très bien expliqué par Herb Sutter dans son Guru Of The Week n°89. Notre compilo n'est pas des plus récents, et il manque donc quelques perles comme la boucle for sur un intervalle, mais l'on peut déjà faire pas mal de trucs rigolos avec les move semantics. Le gain de performances sur un vecteur de shared_ptr lors d'une réallocation est tout à fait remarquable, et quelques jolis graphiques ont vite fait de convaincre nos managers de l'intérêt d'embrasser la modernité.

dimanche 12 mai 2013

Une épingle à nourrice

Voici la modélisation et le rendu d'une épingle à nourrice. Finalement, ça a été plus simple que ce que je pensais. L'épingle a été modélisée en utilisant un chemin Nurbs, comme montré sur l'image en dessous, et un cercle Nurbs utilisé comme bevel object. J'ai utilisé une photo d'épingle en fond afin de me calquer dessus.

Gérer le ressort proprement a été un peu compliqué, puisqu'il a fallu remonter d'un côté et redescendre de l'autre pour ne pas que la boucle rentre en elle-même. Finalement, tout a été fait au pifomètre, et ça ne marche pas trop mal.

Pour la partie qui coince l'épingle, j'ai suivi la bonne vieille méthode de démarrer avec un cube, d'extruder vaguement pour couvrir la forme, et d'appliquer la modification sub-surface jusqu'à ce que ça ressemble à quelque chose.

Et pour finir, un rendu avec fond transparent dans un angle qui cache les parties moches, et basta!

mercredi 8 mai 2013

async_commit=off

J'expérimente ces temps-ci avec l'option "async_commit=off" de Postgresql. Cette option indique au serveur de rendre la main au client dès que le commit est effectué en mémoire, sans attendre que les données soient effectivement écrites sur le disque. L intérêt est donc de découpler la vitesse d'écriture sur le disque dur, et donc de diminuer la latence et d'augmenter le nombre de transactions par seconde.

En contrepartie, si le serveur venait à crasher, quelques secondes de données seraient perdues. Si cette contrainte est acceptable, par exemple parce que les données sont mises à jour régulièrement, ou parce que plusieurs bases tournent derrière un pgPool, c'est un sacré coup de boost.

Voici un petit benchmark qui fait tourner en boucle 1000 transactions, chaque transaction insérant un entier dans une table faite d'une simple colonne, sans contraintes. Le test tourne en local et en distant sur une machine avec lequel j'ai un ping de 200ms, avec synchronous_commit=off et synchronous_commit=on.

L'on voit que les performances augmentent d'environ 30% en local, ce qui est tout à fait appréciable. Mais l'autre chiffre intéressant est la grosse chute de performances en distant: le gain du commit asynchrone reste à peu près identique en relatif, mais la chute est rude. Le fait d'avoir à faire l'aller-retour pour chaque transaction est très coûteux.

La conclusion, c'est que s'il est possible de relâcher ses contraintes d'intégrité, synchronous_commit=off est une manière simple d'obtenir un impressionnant gain de performances. Mais c'est aussi que dans le cas de nombreuses petites transactions, le goulot d'étranglement se trouve sur le réseau, et non sur le disque ou le processeur. Dans ce cas, peut-on imaginer de faire tourner une base en local pour les performances, qui se répliquerait de manière asynchrone sur une base distante utilisée pour le basculement lors d'un crash?

mardi 23 avril 2013

Coder efficacement avec Emacs - Partie 7 - Tramp mode

Le mode "Tramp" d'Emacs permet d'éditer des fichiers distants, typiquement par ssh. En plus de l'édition, toute une série de modes fonctionnent également en distant, notamment la compilation et le debug.

Ma découverte du mode Tramp a commencé lorsqu'il a fallu que je développe depuis ma machine de bureau Windows sur des serveurs Linux situés un peu plus loin que d'habitude. Tout d'un coup, mon installation habituelle à base de Putty + Exceed ou XMing (des serveurs X pour Windows) était horriblement lente. C'est parce que le protocole X est fait pour des réseaux locaux à basse latence, et devient complètement inutilisable même avec 1ms de délai. Une solution est d'utiliser VNC, qui est bien plus efficace dans ces conditions. Une autre est de faire tourner Emacs sur sa machine locale et d'utiliser Tramp.

Son utilisation est simple: il suffit d'ouvrir un fichier via C-x C-f et d'utiliser la syntaxe /ssh:user@machine:~/chemin. L'auto-complétion fonctionne, et l'on peut aller chercher son fichier. Une fois ouvert, on l'édite normalement, et on le sauve sur le chemin distant de manière complètement transparente.

Mais ce sont les modes de compilation et le mode gud qui rendent la fonctionnalité si utile. Une fois un fichier ouvert en distant, une commande de compilation, ou une ouverture du debuger se fera également en distant.

La réactivité d'une application locale, comme si on tournait là-bas!

mercredi 10 avril 2013

Meuh

Un bon mal de crâne avec le framework Android qui n'en fait qu'à sa tête, très mal au bras droit après avoir importé 280 pages dans Confluence parce que mes admins ne savent pas automatiser la chose, des tests unitaires qui foirent parce que l'on a perdu de gros fichiers de données qui seront très difficile à régénérer, la découverte que notre stratégie de gestion des fuseaux horaires est complètement foireuse, mon moral de programmeur n'est pas au beau fixe. Et pourtant, j'ai réussi à convertir mon équipe à IRC, j'ai gagné la bataille des bases de données en imposant Postgresql, et j'arrive à développer sur des machines situés sur des réseaux à haute latence sans avoir à utiliser VNC (simple snobisme), grâce au mode Tramp d'Emacs dont il faudra que je vous cause plus avant. Finalement, les choses vont plutôt bien!

lundi 18 mars 2013

Une goutte

Une goutte très stylisée rendue avec Blender.

Rien de bien méchant, si ce n'est le fond transparent. C'est tout bête, mais encore faut-il savoir comment faire. Tout se passe dans le panneau de rendu. D'abord, désactiver le rendu du "ciel", c'est à dire du fond, dans la section "Layers". Ensuite, rendre l'image avec une composante de transparence en choisissant RGBA. Bien entendu, il faut que le format d'image supporte la transparence, mais PNG, le choix par défaut, le permet.

Et voilà. Fort pratique pour les icônes et logos.

jeudi 14 mars 2013

Reparlons de move semantics

Et voyons si cela change fortement la manière de passer ses paramètres en C++11. Imaginez que vous deviez implémenter une queue d'objets, par exemple pour la rendre thread safe. En c++03, l'on penserait immédiatement à écrire le "push" en passant son paramètre par référence constante, comme montré dans push1. Comparons donc cela avec push2, qui semble au premier abord moins optimal (notez que l'objet A affiche simplement quels sont ses constructeurs appelés):

class Queue
{
public:
  void push1(const A & a)
  {
    _deque.push_back(a);
  }

  void push2(A a)
  {
    _deque.push_back(std::move(a));
  }
  
private:
  std::deque<A> _deque;
};

Voyons ce que cela donne dans le cas général:

Queue q;
A a;
q.push1(a);

affiche

A::A()
A::A(const A &)

Alors que

Queue q;
A a;
q.push2(a);

affiche

A::A()
A::A(const A &)
A::A(const A &&)

C'est à peine pire si l'on part du principe qu'un constructeur move n'est pas cher. Mais maintenant, regardons dans le cas où le paramètre peut être déplacé:

Queue q;
q.push1(A());

affiche

A::A()
A::A(const A &)

ce qui n'est pas pire, mais

Queue q;  
q.push2(A());

affiche

A::A()
A::A(const A &&)

et là, c'est nettement mieux! L'on évite complètement la copie, et l'on déplace simplement l'objet jusqu'à la queue. Notez que

Queue q;
A a;
q.push2(std::move(a));

affiche

A::A()
A::A(const A &&)
A::A(const A &&)

En effet, le standard autorise le compilo à transformer un passage par copie en un move.

Je suis un tout petit peu ennuyé par cette nouvelle approche. En effet, la règle jusqu'ici était, passe par référence si tu peux, et par autre chose si tu dois. Et maintenant, il va falloir choisir entre un passage par référence et un passage par copie en fonction de ce que la fonction va faire avec le paramètre, ce qui me donne l'impression de casser l'encapsulation. Mais économiser des copies est plaisant.

Les labels du blog sont cassés!

Ou plus exactement, le label C++. D'après les forums, tout le monde a le même problème: cliquer sur un label contenant le caractère '+' ne retourne aucun article. En revanche, le compte du nombre d'articles fonctionne...

Ça fait des mois que ça dure. Espérons que Google nous corrige ça bientôt.

vendredi 8 mars 2013

Faire tourner blender + cycles sous Debian

J'avais bien envie d'essayer Cycles, le nouveau moteur de rendu de Blender. Problème: la version présente dans Debian Wheezy ne le supporte pas. En insistant un peu, j'ai quand même réussi à l'extraire des dépôts expérimentaux. Voilà comment:

Tout d'abord, installons la toute dernière version de Blender. Ajoutez les dépôts expérimentaux en éditant /etc/apt/sources.list et en ajoutant:

deb http://ftp.debian.org/debian experimental main

Puis, installons Blender:

aptitude update
aptitude -t experimental install blender

Si vous démarrez Blender maintenant, vous aurez un beau crash. C'est que le paquet expérimental est un peu cassé (du moins chez moi), et qu'il faut aller corriger quelques fichiers. En utilisant strace, j'ai réussi à retrouver les chemins manquants. Tout d'abord, corrigeons le crash en fournissant un répertoire pour les locales, lesquelles sont cherchées notamment dans /usr/share/blender/2.66/datafiles/locale:

cd /usr/share/blender
mkdir 2.66
cd 2.66
mkdir datafiles
cd datafiles
mkdir locale

Si vous démarrez Blender après ceci, il démarrera, mais tous les menus seront vides: en effet, il y a un autre souci de chemin et Blender ne trouve pas les scripts Python qui le font tourner, car il les cherche dans /usr/share/blender/2.66/scripts alors qu'ils sont directement dans /usr/share/blender/scripts. Recollons les wagons:

cd /usr/share/blender/2.66
ln -s ../scripts .

Et là miracle, Blender démarre correctement, et Cycles marche comme sur des roulettes.

jeudi 28 février 2013

Blender et moteur physique

Voici une petite animation d'une boule rencontrant un mur de briques

L'animation a été générée en construisant le mur et la boule dans le "Game Engine", puis en ajoutant une force à la boule dans la bonne direction. L'animation est ensuite enregistrée, et la scène peut alors être retravaillée dans le mode rendu.

Cela m'ouvre des horizons quant à la manière de gérer ses animations, en comptant beaucoup plus sur le "Game Engine" et ses scripts visuels plutôt que d'enregistrer des keyframes.

dimanche 24 février 2013

Terre, rendu en haute définition

Nouvelle vidéo de notre bonne vieille planète. Cette fois-ci, j'ai rendu 1 minute de rotations en haute définition. Ma machine a trimé une bonne partie de la nuit, avec environ 6 heures à maximiser mes 4 CPUs.

samedi 23 février 2013

Mon rendu de la planète terre

Je suis tombé sur l'excellent tutoriel d'Andrew Price sur comment modéliser la planète Terre dans Blender, à partir des images de la NASA. Du tutoriel, je retiendrait la puissance des nœuds de matériaux, qui permet notamment de sélectionner la texture "jour" ou la texture "nuit" via la couleur de rendu d'un matériau postiche, et la puissance des nœuds du mode de composition qui permettent notamment des effets de halos qui rendent particulièrement bien.

Également, le raccourci du jour: Ctrl-Alt-Num0 déplace la caméra de manière à rendre ce que vous voyez dans la vue courante. Beaucoup plus pratique que de se battre à déplacer manuellement la caméra au bon endroit!

Voici d'abord l'image:

Et voici également la vidéo:

dimanche 10 février 2013

Ces jeux qui m'ont marqué - Landstalker

Quittons un instant le monde des ordinateurs dits "de bureau", et arrêtons nous du côté de la Sega Megadrive, pour jeter un coup d’œil à Landstalker. Landstalker est un RPG en vue isométrique, où vous incarnez un elfe chasseur de trésor rencontrant une petite fée qui dit savoir où se trouvent les trésors du roi Nole. Il n'en faut pas plus pour se lancer!

Ce qui frappe quand on commence à jouer à Landstalker, c'est bien évidemment cette 3D isométrique. Parce qu'elle permet également de se déplacer en hauteur via marches, escaliers, ponts, tunnels, étagères, corniches, ce sont des mondes beaucoup plus complexes qui sont disponibles, avec les énigmes qui vont avec. Le monde en lui même est riche et cohérent, composé de villages et de villes reliés par des chemins mal fréquentés, menant parfois à des ruines ou des cavernes contenant un élément essentiel pour faire avancer l'histoire. Dans les villes, l'on pourra entrer chez les gens qui auront souvent des choses intéressantes à dire, se réapprovisionner auprès des commerçants, ou jouer à des mini-jeux. La quête pour les trésors du Roi est entrecoupée de sous-quêtes où l'on pourra aider un villageois enlevé par des brigands ou déjouer un complot à la cour du roi local. Une équipe de chasseurs de trésors concurrente nous met régulièrement des bâtons dans les roues.

C'est souvent l'impression de liberté qui me permet de rentrer dans le jeu, et de ce côté là, Landstalker fait très fort. L'histoire est linéaire, mais reste suffisamment vague sur les détails pour nécessiter de l'exploration. Le monde est rempli de passages secrets et autre caches permettant d'amasser des sous ou de l'équipement, et il est possible de parler à tout le monde (et même aux animaux). L'humour est omniprésent, ainsi qu'une petite dose de grivoiserie, le héros étant tout à fait intéressé par les jeunes filles, et la petite fée jalouse comme une tigresse.

Les musiques sont très entraînantes, mais parfois un peu répétitives, puisqu'il s'agit du même morceau d'environ 1 minute mis en boucle pour chaque atmosphère (donjon, village, campagne...). De fait, c'est quasiment hypnotique, et je peux encore les chanter pratiquement toutes par cœur plus de 15 ans après y avoir joué.

Le jeu est terriblement difficile (j'étais loin de l'avoir fini à l'époque) et les boss sont redoutables. Il est parfois trop facile de se retrouver à tourner en rond, et du temps où Internet n'existait pas, l'on pouvait se prendre la tête pendant des heures sans trouver l'astuce pour continuer.

Landstalker est sorti sur la console virtuelle sur WII. C'est tentant, non?

samedi 2 février 2013

Laisser le temps au temps

Parlons un peu des routines de la libc que sont localtime_r, gmtime_r, mktime, et timegm. Ces fonctions sont utilisées pour convertir l'heure Unix (le nombre de secondes depuis le premier Janvier 1970) en une structure tm qui contient année, mois, jour, heure, minute et seconde, et inversement, en utilisant l'heure locale ou l'UTC.

Il est donc raisonable pour localtime_r et pour mktime d'accéder à la variable d'environnement TZ pour obtenir le fuseau horaire nécessaire aux conversions en temps local. Il est également raisonnable de protéger ladite variable d'environnement par un beau mutex global. Les performances s'écroulent lorsque trop de threads cherchent à faire des conversions de dates (imaginons par exemple un système de log multithreadé).

Ce qui est moins raisonnable, c'est que beaucoup d'implémentations de gmtime_r et timegm (notamment dans la glibc de RHEL5) utilisent les mêmes routines que localtime_r et mktime, et donc tentent d'acquérir le mutex global quand bien même elles n'en ont aucunement besoin, puisqu'il n'y a pas d'ajustement de fuseau horaire à effectuer. Les performances sont meilleures (6x plus rapide sur mon benchmark) car les calculs sont plus simples, mais il y a encore ce mutex qui s'obstine à nous pourrir la vie.

En allant regarder du côté de FreeBSD, on trouve en revanche des implémentations directes, sans mutex, des fonctions sus-citées. Collons ça dans le code, et c'est un facteur 3 qui est gagné.

La conclusion, c'est que pour faire quoi que ce soit d'avancé avec les dates, il n'y a pas trop le choix: il faut écrire sa propre classe DateTime, extraire les données brutes des fuseaux horaires depuis la tz database, faire soi-même les ajustements, et importer du code lock-free pour ses conversions.

mercredi 23 janvier 2013

Janvier qui se termine...

Et je n'ai posté qu'une seule fois depuis le début de l'année? Pas bien.

Pourtant, je fais des choses. Un poil de développement Android, par exemple. C'est fascinant, et plutôt facile de débuter (merci Java!). Par contre, il faut avoir du talent et de l'imagination pour trouver quelque chose à faire d'original, lorsque l'on voit que toutes les bonnes idées (et un grand nombre de mauvaises également) ont déjà 50 apps gratuites.

J'aimerais bien développer en natif sur une tablette libre GNU/Linux, mais sans nouvelles de la Vivaldi depuis la mi-Septembre, j'ai peu d'espoir. C'est surtout que même si les apps Android sont généralement bien fichues, elles sont souvent soit payantes, soit blindées de pubs, alors qu'il existe bien mieux dans l'écosystème Linux. Donnez-moi Debian sur un téléphone, et je n'ai pas besoin de leur app-store (ce qui explique très certainement que personne ne vende un téléphone avec Debian dessus, les constructeurs savent bien que c'est l'app store qui rapporte).

Reste que tout ça ne remplacera jamais un PC de bureau. Essayez donc de vous chauffer avec un téléphone!

mardi 1 janvier 2013

Les bases de l'animation - Rotations

Je reprends tout depuis le début (et je n'étais déjà pas loin). Voilà comment encoder une animation de rotation, en l'occurrence les ailes d'un moulin. Commençons donc avec un bête moulin, et ses hélices jointes en un objet unique pour se simplifier la vie:

Encodons la première position: pour ce faire, allez dans le menu "Keyframes" => "Insert" dans le menu Object Tools à gauche, ou pressez la touche "i". Choisir "Rotation". Puis se déplacer quelques frames plus loin, par exemple 20:

Nous pouvons maintenant effectuer la rotation du l'hélice. Dans mon cas, il m'a fallu changer le mode de rotation, car mon X était confondu avec mon Z. En passant en mode "ZXY Euler", j'ai pu changer mon Z à 80°, ce qui a fait tourner l'hélice sur son axe. L'on peut refaire une keyframe pour la rotation.

Revenez en arrière et faites "Play". L'hélice prend de la vitesse, puis ralentit, avant de s'arrêter à la frame 20. En effet, par défaut, Blender effectue une interpolation de Bézier et une extrapolation constante. Changeons tout cela en passant en mode "Graph editor", et en sélectionnant "View" => "View all" dans le menu.

Sélectionnez la seconde keyframe de la courbe, et allez dans "Channel" => "Extrapolation mode" => "Linear extrapolation". La courbe est maintenant droite, et jouer l'animation confirme que l'hélice tourne à vitesse constante pendant toute la durée de la vidéo. Plus qu'à exporter!