février
2013
Pour le troisième volet de cet article je vais discuter la fonction auxiliaire à laquelle je faisais allusion dans la première partie. Nous allons premièrement voir quel est le problème qu’il s’agit de résoudre.
Le problème des appels de fonction
Revenons au programme fzero que l’on avait traduit en C dans le volet précédent de cet article:
int choix = 0; while (1) switch (choix) { case 0: if (n == 0) choix = 1; else choix = 2; break; case 1: return c_return; case 2: n = n - 1; choix = 0; break; default: c_throw->event.message = "Erreur de branchement!"; return c_throw; }
Ce qui est notable c’est qu’il s’agit d’une fonction très simple. En particulier, cette fonction ne fait pas appel à d’autres fonctions dodo: le test if, les opérations n == 0 et n = n – 1 sont directement écrits en C ici.
Mais si elle contient un appel de fonction, d’après la logique du language dodo fzero devrait lui fournir une continuation à invoquer quand la fonction veut retourner à l’appelant.
Si l’on s’en tient à la convention d’une fonction C par fonction dodo, cela signifie que l’on devrait pouvoir sauter au milieu de la boucle while avec une branche (valeur de choix) différente de zéro.
Une solution
Une solution simple à cela serait de passer en tant que continuation non seulement la fonction à appeler, mais aussi la branche où il faut se rendre. Mais il peut y avoir d’autres données à inclure dans la continuation comme les paramètres de la fonction (n dans cet exemple). Si bien que la solution retenue utilise une structure C pour stocker l’adresse de la fonction, la branche et les autres données.
typedef void* (*continuation)(void*); struct fzero_data { continuation* function; int choice; int n; continuation** c_return; continuation** c_throw; };
Ce qui est intéressant est que cela correspond à ce à quoi l’on s’attend pour une closure écrite en C. Il n’y a rien de bien étonnant à ça, comme j’avais dit auparavant il est facile de traduire les continuations de dodo en closures dans un language de programmation qui en dispose.
Exemple pratique
A ce point nous pouvons appeler une autre fonction dodo depuis la boucle while en spécifiant l’adresse de data comme continuation de retour. Par exemple, nous allons appeler une fonction qui écrit un texte à l’écran.
Nous pouvons donc utiliser la structure ci-dessus dans notre fonction:
continuation** fzero(int n, continuation** c_return, continuation** c_throw); continuation** fzero_switch(struct fzero_data* data) { int choix = data->choix; while (1) switch (choix) { case 0: if (data->n == 0) choix = 1; else choix = 2; break; case 1: return data->c_return; case 2: data->choix = 3; return printHello((continuation**) data, c_throw); case 3: data->n = data->n - 1; choix = 0; break; default: ((struct event_handler*) data->c_throw)->event.message = "Erreur de branchement!"; return data->c_throw; } }
La fonction fzero déclarée ci-dessus sera expliquée dans un prochain volet, mais nous pouvons déjà comprendre qu’elle crée une structure fzero_data avec les paramètres de la fonction puis appelle la fonction auxiliaire fzero_switch.