<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Le nid de dodo &#187; Technique</title>
	<atom:link href="https://blog.developpez.com/dodo/pcategory/technique/feed" rel="self" type="application/rss+xml" />
	<link>https://blog.developpez.com/dodo</link>
	<description></description>
	<lastBuildDate>Sat, 19 Oct 2024 00:29:26 +0000</lastBuildDate>
	<language>fr-FR</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.1.42</generator>
	<item>
		<title>Faire dodo en C &#8211; Partie 3</title>
		<link>https://blog.developpez.com/dodo/p11806/technique/faire-dodo-en-c-partie-3</link>
		<comments>https://blog.developpez.com/dodo/p11806/technique/faire-dodo-en-c-partie-3#comments</comments>
		<pubDate>Tue, 26 Feb 2013 10:01:47 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false">http://blog.developpez.com/dodo/?p=33</guid>
		<description><![CDATA[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&#8217;il s&#8217;agit de résoudre. Le problème des appels de fonction Revenons au programme fzero que l&#8217;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; [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>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&rsquo;il s&rsquo;agit de résoudre.<br />
<span id="more-33"></span></p>
<h2>Le problème des appels de fonction</h2>
<p>Revenons au programme <strong>fzero</strong> que l&rsquo;on avait traduit en C dans le volet précédent de cet article:</p>
<pre>   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-&gt;event.message = "Erreur de branchement!";
         return c_throw;
   }</pre>
<p>Ce qui est notable c&rsquo;est qu&rsquo;il s&rsquo;agit d&rsquo;une fonction très simple. En particulier, cette fonction ne fait pas appel à d&rsquo;autres fonctions dodo: le test <em>if</em>, les opérations <em>n == 0</em> et <em>n = n &#8211; 1</em> sont directement écrits en C ici.</p>
<p>Mais si elle contient un appel de fonction, d&rsquo;après la logique du language dodo <strong>fzero</strong> devrait lui fournir une continuation à invoquer quand la fonction veut retourner à l&rsquo;appelant.</p>
<p>Si l&rsquo;on s&rsquo;en tient à la convention d&rsquo;une fonction C par fonction dodo, cela signifie que l&rsquo;on devrait pouvoir sauter au milieu de la boucle <em>while</em> avec une branche (valeur de <em>choix</em>) différente de zéro.</p>
<h2>Une solution</h2>
<p>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&rsquo;autres données à inclure dans la continuation comme les paramètres de la fonction (<em>n</em> dans cet exemple). Si bien que la solution retenue utilise une structure C pour stocker l&rsquo;adresse de la fonction, la branche et les autres données.</p>
<pre>typedef void* (*continuation)(void*);

struct fzero_data
{
   continuation* function;
   int choice;
   int n;
   continuation** c_return;
   continuation** c_throw;
};</pre>
<p>Ce qui est intéressant est que cela correspond à ce à quoi l&rsquo;on s&rsquo;attend pour une closure écrite en C. Il n&rsquo;y a rien de bien étonnant à ça, comme j&rsquo;avais dit auparavant il est facile de traduire les continuations de dodo  en closures dans un language de programmation qui en dispose.</p>
<h2>Exemple pratique</h2>
<p>A ce point nous pouvons appeler une autre fonction dodo depuis la boucle while en spécifiant l&rsquo;adresse de <em>data</em> comme continuation de retour. Par exemple, nous allons appeler une fonction qui écrit un texte à l&rsquo;écran.</p>
<p>Nous pouvons donc utiliser la structure ci-dessus dans notre fonction:</p>
<pre>continuation** fzero(int n, continuation** c_return, continuation** c_throw);

continuation** fzero_switch(struct fzero_data* data)
{
   int choix = data-&gt;choix;
   while (1) switch (choix)
   {
      case 0:
         if (data-&gt;n == 0) choix = 1;
         else choix = 2;
         break;
      case 1:
         return data-&gt;c_return;
      case 2:
         data-&gt;choix = 3;
         return printHello((continuation**) data, c_throw);
      case 3:
         data-&gt;n = data-&gt;n - 1;
         choix = 0;
         break;
      default:
         ((struct event_handler*) data-&gt;c_throw)-&gt;event.message =
            "Erreur de branchement!";
         return data-&gt;c_throw;
   }
}</pre>
<p>La fonction <strong>fzero</strong> déclarée ci-dessus sera expliquée dans un prochain volet, mais nous pouvons déjà comprendre qu&rsquo;elle crée une structure <em>fzero_data</em> avec les paramètres de la fonction puis appelle la fonction auxiliaire <strong>fzero_switch</strong>.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Faire dodo en C &#8211; Partie 2</title>
		<link>https://blog.developpez.com/dodo/p11189/technique/faire_dodo_en_c_partie_2</link>
		<comments>https://blog.developpez.com/dodo/p11189/technique/faire_dodo_en_c_partie_2#comments</comments>
		<pubDate>Sat, 28 Jul 2012 20:14:01 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le langage dodo et le langage C ne sont pas trop éloignés au niveau de la syntaxe, mais leur fonctionnement est assez différent. Là où C est un langage procédural, dodo est un langage à prototypes utilisant le passage de continuations (CPS). Le défi pour moi, l&#8217;architecte du langage, est de faire correspondre les concepts de dodo à une implémentation pratique offrant une performance acceptable. Je me suis donc tourné vers C avec l&#8217;idée d&#8217;écrire [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Le langage dodo et le langage C ne sont pas trop éloignés au niveau de la syntaxe, mais leur fonctionnement est assez différent. Là où C est un langage <a href="http://fr.wikipedia.org/wiki/Programmation_procédurale">procédural</a>, dodo est un <a href="http://fr.wikipedia.org/wiki/Programmation_orientée_prototype">langage à prototypes</a> utilisant le <a href="http://fr.wikipedia.org/wiki/Continuation">passage de continuations (CPS)</a>.</p>
<p>Le défi pour moi, l&rsquo;architecte du langage, est de faire correspondre les concepts de dodo à une implémentation pratique offrant une performance acceptable. Je me suis donc tourné vers C avec l&rsquo;idée d&rsquo;écrire un convertisseur automatique de programmes dodo en C.</p>
<p>Seulement voilà, comment traduire?<br />
<span id="more-11"></span><br />
<strong>La directive switch<br />
</strong><br />
Comme je l&rsquo;ai suggéré dans <a href="http://blog.developpez.com/dodo/p11170/technique/faire-dodo-en-c/">la première partie</a>, l&rsquo;appel de continuation en dodo et la directive <code class="codecolorer text default"><span class="text">switch</span></code> de C s&rsquo;apparentent tous deux à <em>GOTO</em>, alors on peut écrire quelque chose comme:</p>
<pre>
   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-&gt;event.message = "Erreur de branchement!";
         return c_throw;
   }
</pre>
<p>Cela correspond à une fonction dodo qui prend en paramètre un nombre <em>n</em> et le décrémente jusqu&rsquo;à ce qu&rsquo;il atteigne 0, puis retourne de la fonction:</p>
<pre>
   def fzero = fun(int n) =&gt; return(), throw(Exception):
      n = 0 -&gt;
         return()
      |
         n - 1 -&gt; n
         $fzero(n)
   .
</pre>
<p><strong>La notation à continuations</strong></p>
<p>Le code dodo ci-dessus ne ressemble pas vraiment à du C vous me direz. C&rsquo;est que j&rsquo;ai utilisé la notation à continuations pour bien illustrer la correspondance avec le <code class="codecolorer text default"><span class="text">switch</span></code>. En réalité, le but est bien de pouvoir écrire la fonction <code class="codecolorer text default"><span class="text">fzero</span></code> en style C comme ceci:</p>
<pre>
   def fzero(int n)
   {
      loop
      {
         case if (n = 0)
         {
            return()
         }
         .n = n - 1
      }
   }
</pre>
<p>À quoi bon transformer une fonction de style C en une fonction à passage de continuations, pour ensuite la transformer à nouveau en fonction C vous demandez-vous?</p>
<p>Hé bien pour le moment je compte implémenter juste la notation à continuations, de façon à avoir une base solide pour le langage, et ensuite m&rsquo;attaquer à la transformation du style procédural en passage de continuations pour rendre le langage plus confortable à utiliser. Si un jour je trouve un langage avec continuations ou <em>GOTO</em> que je peux utiliser en lieu et place de C, il devrait être simple d&rsquo;implémenter le langage de base de dodo avec lui. Le reste de dodo n&rsquo;aura pas besoin d&rsquo;être réécrit.</p>
<p><strong>La boucle de continuations</strong></p>
<p>Revenons à nos moutons.</p>
<p>Nous avons vu comment utiliser <code class="codecolorer text default"><span class="text">switch</span></code> pour implémenter une fonction dodo simple qui se contente de décrémenter un compteur.</p>
<p>Pour ceux qui sont attentifs, il y a une continuation dans le <code class="codecolorer text default"><span class="text">switch</span></code> qui n&rsquo;existe pas dans la fonction dodo: celle du cas <em>default</em>. Un examen du code montre que ce cas n&rsquo;est jamais atteint, mais il est bon de prévoir une erreur du convertisseur automatique (ou dans ce cas, du convertisseur humain puisque c&rsquo;est écrit à la main!)</p>
<p>
<hr /></p>
<p>Si je parle du cas <em>default</em> c&rsquo;est que ses instructions contiennent une ligne intéressante qu&rsquo;il serait bon d&rsquo;expliquer. C&rsquo;est:</p>
<pre>
   c_throw-&gt;event.message = "Erreur de branchement!";
</pre>
<p>On y voit comment passer un paramètre à une continuation. En effet, <em>c_throw</em> est une continuation passée en paramètre à la fonction C. Il ne serait pas viable d&rsquo;utiliser la technique du <code class="codecolorer text default"><span class="text">switch</span></code> pour toutes les continuations du programme, dans une application conséquente il y aurait des centaines de milliers de cas dans le <code class="codecolorer text default"><span class="text">switch</span></code>, sans compter qu&rsquo;il faudrait trouver comment faire passer des arguments à une continuation sans mettre tout en variables globales.</p>
<p>Donc on garde la boucle de continuation décrite <a href="http://blog.developpez.com/dodo/p9236/technique/vers-une-premiere-implementation-de-dodo/">dans un article précédent</a> pour interagir avec les autres fonctions.</p>
<p>Mais la boucle de continuation utilise des fonctions qui sont appelées en boucle, comment se fait-il que l&rsquo;exemple utilise la notation <code class="codecolorer text default"><span class="text">c_throw-&amp;gt;event</span></code> qui suggère que <em>c_throw</em> est une structure pas une fonction?</p>
<p>C&rsquo;est simple, <em>c_throw</em> est effectivement une structure. Mais son premier champ est un pointeur de fonction qui est utilisé par la boucle de continuations. Dans l&rsquo;exemple donné, <em>event</em> est un autre champ de la structure. La boucle de continuations ne sait rien de <em>event</em>, ou des autres champs ajoutés à la structure.</p>
<p>Il faut que la fonction appelée par la boucle de continuations puisse lire une valeur fournie comme argument par l&rsquo;appelant de la continuation qui, lui, connaît la structure de c_throw.</p>
<p>C&rsquo;est pour cela que la boucle de continuation passe la structure en argument à la fonction. Dès lors, voici comment s&rsquo;écrit la boucle de continuations:</p>
<pre>
   continuation suivante = premiere
   while (suivante != NULL)
   {
      suivante = suivante-&gt;appel(suivante);
   }
</pre>
<p><strong>Gestion de la mémoire</strong></p>
<p>Donc <em>event</em> est un champ de la structure passée en argument à la fonction C pour la continuation <em>c_throw</em>. Côté dodo il correspond à un argument de la continuation <code class="codecolorer text default"><span class="text">throw</span></code>. Mais comment le programme alloue-t-il la mémoire pour les champs supplémentaires de la structure?</p>
<p>
<hr /></p>
<p>La boucle de continuations ne peut pas gérer cela, elle ne sait rien des champs supplémentaires et de plus elle ne saurait pas quand la mémoire n&rsquo;est plus nécessaire et peut être libérée.</p>
<p>L&rsquo;appelant pourrait utiliser <code class="codecolorer text default"><span class="text">malloc</span></code> pour allouer la mémoire nécessaire. La mémoire pourrait être libérée au retour si elle n&rsquo;est plus utilisée. C&rsquo;était de fait ma première idée.</p>
<p>Un problème est que le contrôle ne retourne pas nécessairement à l&rsquo;appelant quand la fonction termine. Un exemple courant est une fonction qui passe à une fonction appelée sa propre continuation <code class="codecolorer text default"><span class="text">return</span></code> comme continuation de retour. Quand la fonction appelée fait <code class="codecolorer text default"><span class="text">return()</span></code>, la fonction qui l&rsquo;a appelée n&rsquo;est pas informée.</p>
<p>Il faut donc intercepter cela pour libérer la mémoire allouée, avant que la continuation n&rsquo;atteigne la boucle de continuations.</p>
<p>C&rsquo;est alors qu&rsquo;une autre idée m&rsquo;est venue.</p>
<p>Plutôt que d&rsquo;essayer de libérer la mémoire quand elle n&rsquo;est plus utilisée, pourquoi n&rsquo;essaierions-nous pas de préserver la mémoire qui sera encore utilisée jusqu&rsquo;au retour de la fonction?</p>
<p>Pour cela, on dissocie la fonction dodo en deux fonctions C: l&rsquo;une qui fait le travail et contient le <code class="codecolorer text default"><span class="text">switch</span></code>, et l&rsquo;autre qui préserve la mémoire utile jusqu&rsquo;à la fin de la fonction et qui contient une boucle de continuations. La fonction au <code class="codecolorer text default"><span class="text">switch</span></code> n&rsquo;utilise la boucle de continuations que pour reprendre le contrôle quand une fonction appelée retourne ou pour terminer. La boucle de continuations continue tant que la continuation suivante appelle la fonction au <code class="codecolorer text default"><span class="text">switch</span></code> (qui n&rsquo;est donc pas terminée).</p>
<p>Il n&rsquo;y a pas besoin d&rsquo;utiliser <code class="codecolorer text default"><span class="text">malloc</span></code> avec cette solution, la mémoire peut être préservée sur la pile.</p>
<p>Par exemple, si notre fonction <em>fzero</em> voulait afficher la valeur de <em>n</em> à chaque itération on pourrait écrire les deux fonctions:</p>
<pre>
   continuation fzero(int n, continuation c_return, continuation c_throw)
   {
      struct c_fzero donnees = {
         fzero_switch, // appel
         0,            // choix
         n,
         c_return,
         c_throw
      }
      continuation suivante = (continuation) &amp;donnees;
      while (suivante-&gt;appel == fzero_switch)
      {
         suivante = suivante-&gt;appel(suivante);
      }
      return suivante;
   }

   continuation fzero_switch(continuation self)
   {
      struct c_fzero *donnees = (struct c_fzero*) self;
      int choix = donnees-&gt;choix;
      int n = donnees-&gt;n;
      while (1) switch (choix)
      {
         case 0:
            if (n == 0) choix = 1;
            else choix = 2;
            break;
         case 1:
            return donnees-&gt;c_return;
         case 2:
            donnees-&gt;choix = 3;
            donnees-&gt;n = n;
            return print_int(n, self, donnees-&gt;c_throw);
         case 3:
            n = n - 1;
            choix = 0;
            break;
         default:
            donnees-&gt;c_throw-&gt;event.message = "Erreur de branchement!";
            return donnees-&gt;c_throw;
      }
   }
</pre>
<p>On voit que si <em>print_int</em> retourne <em>self</em>, la boucle de continuation appelle à nouveau <em>fzero_switch</em> mais avec le choix 3. Par contre si elle retourne la continuation <code class="codecolorer text default"><span class="text">throw</span></code>, la boucle de continuation de <em>fzero</em> termine.</p>
<p>Je conclus ainsi la seconde partie de <strong><a href="http://blog.developpez.com/dodo/p11170/langage/faire_dodo_en_c" title="Faire dodo en C">Faire dodo en C</a></strong>.</p>
<p>Vous pouvez réagir dans les commentaires ci-dessous.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Une table associative efficace basée sur deux principes</title>
		<link>https://blog.developpez.com/dodo/p11178/technique/une_table_associative_efficace_basee_sur</link>
		<comments>https://blog.developpez.com/dodo/p11178/technique/une_table_associative_efficace_basee_sur#comments</comments>
		<pubDate>Fri, 27 Jul 2012 13:11:21 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Flânerie]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Table de hachage La table de hachage est une structure de données qui permet d&#8217;implémenter une table associative (que l&#8217;on appelle aussi un index ou un dictionnaire). Son principe est de répartir les données de façon homogène à l&#8217;aide d&#8217;une fonction de hachage appliquée aux clés de la table. La plupart des langages de programmation offrent une table de hachage comme structure de données standard, avec peut-être l&#8217;exception notable du langage C (noter que le [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><strong>Table de hachage</strong></p>
<p>La <em><a href="http://fr.wikipedia.org/wiki/Table_de_hachage">table de hachage</a></em> est une structure de données qui permet d&rsquo;implémenter une <a href="http://fr.wikipedia.org/wiki/Tableau_associatif">table associative</a> (que l&rsquo;on appelle aussi un <em>index</em> ou un <em>dictionnaire</em>). Son principe est de répartir les données de façon homogène à l&rsquo;aide d&rsquo;une <em><a href="http://fr.wikipedia.org/wiki/Fonction_de_hachage">fonction de hachage</a></em> appliquée aux clés de la table.</p>
<p>La plupart des langages de programmation offrent une table de hachage comme structure de données standard, avec peut-être l&rsquo;exception notable du langage C (noter que le C++ comble cette lacune).</p>
<p>Mais est-il possible de faire mieux que la table de hachage proposée par défaut?<br />
<span id="more-10"></span><br />
<strong>Mesure du mieux</strong></p>
<p>Il y a différentes mesures qui déterminent la qualité d&rsquo;une table de hachage.</p>
<p>L&rsquo;une d&rsquo;elle est le<em> taux de remplissage</em> &#8211; est-ce que la table accommode un certain nombre d&rsquo;éléments sans laisser trop de &laquo;&nbsp;trous&nbsp;&raquo;?</p>
<p>Une autre est l&rsquo;efficacité de consultation, et l&rsquo;efficacité d&rsquo;insertion. Je ne parlerai pas de l&rsquo;efficacité d&rsquo;enlever un élément.</p>
<p>Un facteur clé pour améliorer le taux de remplissage est une bonne fonction de hachage. Par exemple, si la fonction de hachage ne retourne jamais que des nombres entre <em>0</em> et <em>100</em>, il est inévitable que plusieurs clés aient la même valeur de hachage après une centaine d&rsquo;insertions. Même si la table de hachage se redimensionne pour accommoder plus d&rsquo;éléments, ce sera en vain car tous les éléments vont se retrouver aux emplacements correspondants aux nombres de 0 à 100, en fait c&rsquo;est contre-productif puisque le taux de remplissage se détériore!</p>
<p>La solution proposée dans cet article ne permet pas de compenser une mauvaise fonction de hachage. En fait elle est plus exigeante que les solutions traditionnelles car elle fait appel à plusieurs fonctions de hachage pour chaque clé.</p>
<p><strong>Le principe de la seconde chance</strong></p>
<p>Utiliser deux (ou davantage) fonctions de hachage est la base de la première astuce qui va nous permettre d&rsquo;écrire une table de hachage super efficace, le <em>principe de la seconde chance</em>.</p>
<p>Etant donné une fonction de hachage <em>h1</em> et une clé <em>k</em>, comment décider où placer l&rsquo;élément dans la table de hachage? Une table de hachage fait généralement appel à un tableau de taille fixe (<em>N</em>) pour stocker les données, donc il s&rsquo;agit de faire correspondre le numéro retourné par <code class="codecolorer text default"><span class="text">h1(k)</span></code> avec un numéro d&rsquo;index dans ce tableau. </p>
<p>Cela se fait souvent avec l&rsquo;opération <em>modulo</em>, c&rsquo;est-à-dire le reste de la division <code class="codecolorer text default"><span class="text">h1(k) / N</span></code>. Le modulo donne un nombre entre <em>0</em> et<em> N-1</em> qui est utilisée comme valeur d&rsquo;index.</p>
<p>Si je rappelle tout cela, c&rsquo;est pour mettre en exergue le fait qu&rsquo;une tâche de la table de hachage est de gérer les <em>collisions</em>. En effet, il y a plusieurs valeurs telles que, par exemple, <code class="codecolorer text default"><span class="text">x modulo 100</span></code> est égal à 13. Si la valeur de hachage est 13, 113, 213, 313 etc il faut lui trouver une place même s&rsquo;il y a déjà un élément à l&rsquo;emplacement prévu.</p>
<p>Une solution est de rechercher un autre emplacement possible pour l&rsquo;élément. Le principe de la seconde change utilise une différente fonction de hachage, disons <em>h2</em>, pour déterminer cet autre emplacement. Il est important que <em>h1</em> et <em>h2</em> soient indépendants, autrement il y a des chances que les deux fonctions retournent les mêmes deux résultats pour différentes clés.</p>
<p>Donc l&rsquo;algorithme est:</p>
<pre>p1 = h1(k) modulo N
si libre(p1)
  alors table[p1] = paire(k, élément)
sinon
  p2 = h2(k) modulo N
  si libre(p2)
    alors table[p2] = paire(k, élément)
</pre>
<p>Il est possible d&rsquo;utiliser davantage de fonctions de hachage de la même façon que h2.</p>
<p>Pour retrouver un élément, on regarde aux différents emplacements possible pour voir s&rsquo;ils contiennent la clé recherchée.</p>
<p>Si tous les emplacements sont déjà pris, il peut être nécessaire de redimensionner le tableau — ce qui donne un nouvel <em>N</em> et permet, on l&rsquo;espère, de placer l&rsquo;élément.</p>
<p>Il n&rsquo;est pas très satisfaisant de devoir compter sur un <em>N</em> qui a exactement la bonne valeur pour pouvoir placer un élément, d&rsquo;autant plus qu&rsquo;il est coûteux de redimensionner la table de hachage car tous les éléments prennent un nouvel emplacement. L&rsquo;efficacité de consultation est très bonne mais utilisé seul, le principe de seconde chance donne un taux de remplissage avoisinant les 50%.</p>
<p><strong>Le principe du coucou</strong></p>
<p>Pour améliorer cela, on utilise une autre astuce: <em>le principe du <a href="http://en.wikipedia.org/wiki/Cuckoo_hashing">coucou</a></em>. Le bébé coucou, il est bien connu, est né dans le nid d&rsquo;autres oiseaux et se fait de la place en jetant les oeufs du nid par-dessus bord. Pour une table de hachage, l&rsquo;idée est de faire de la place en déplaçant l&rsquo;élément existant <em>autre part</em>.</p>
<p>Certains utilisent les fonctions de hachage pour trouver un nouvel emplacement à l&rsquo;élément existant dans la table de hachage. S&rsquo;il n&rsquo;y a pas d&rsquo;emplacement libre, il peut y avoir des déplacements en cascade. Mais <a href="http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.185.2655&#038;rep=rep1&#038;type=pdf">une étude a montré</a> qu&rsquo;un seul déplacement par insertion est nécessaire pour une bonne efficacité.</p>
<p>Ma solution, de son côté, utilise une <em>réserve</em> pour les éléments existants déplacés. Dans mes tests, en utilisant une table de hachage de 50 à 100 éléments comme réserve, le taux de remplissage excède facilement 90% pour l&rsquo;insertion de 250 à 10000 éléments jusqu&rsquo;à saturation.</p>
<p>C&rsquo;est tout bonnement excellent pour une solution aussi simple et économe en espace mémoire.</p>
<p>L&rsquo;algorithme combinant <em>le principe de seconde chance</em> avec deux fonctions de hachage, <em>le principe du coucou</em> et une réserve est:</p>
<pre>p1 = h1(k) modulo N
si libre(p1)
  alors table[p1] = paire(k, élément)
sinon
  p2 = h2(k) modulo N
  si libre(p2)
    alors table[p2] = paire(k, élément)
  sinon
    p = choix(p1 ou p2)
    ajoute(réserve, table[p])
    table[p] = paire(k, élément)
</pre>
<p>Si la réserve est pleine on a le choix de redimensionner le tableau ou la réserve. Je pense que l&rsquo;idéal est d&rsquo;augmenter les deux jusqu&rsquo;à ce que la taille de la réserve soit trop grande pour être stockée dans une ligne de cache ou une page de mémoire, puis n&rsquo;augmenter que la taille du tableau. Mes tests montrent qu&rsquo;il n&rsquo;y a pas d&rsquo;avantage à avoir une très grande réserve.</p>
<p>Pour la réserve on peut utiliser une table de hachage comme je l&rsquo;ai fait ou on peut utiliser une liste ordonnée par valeur de hachage, dont l&rsquo;ordre peut être maintenu de façon efficace pour un nombre d&rsquo;éléments restreint (<code class="codecolorer text default"><span class="text">O(log N)</span></code> pour la consultation et pour l&rsquo;insertion). L&rsquo;avantage est que la liste ordonnée peut accepter des éléments dont toutes les valeurs de hachage sont identiques.</p>
<p><strong>Problème: je n&rsquo;ai qu&rsquo;une seule fonction de hachage!</strong></p>
<p>Souvent en standard on n&rsquo;a qu&rsquo;une seule fonction de hachage à disposition, par exemple en Java il y a <code class="codecolorer text default"><span class="text">x.hashCode()</span></code>. Dans le cas d&rsquo;un objet composé de plusieurs attributs, on peut simplement prendre les attributs uniques à l&rsquo;objet et utiliser leurs fonctions de hachage.</p>
<p>Il y a un autre moyen. Puisque l&rsquo;index dans le tableau est calculé à l&rsquo;aide de <code class="codecolorer text default"><span class="text">h1(k) modulo N</span></code>, le résultat non fractionnaire de la division n&rsquo;entre pas en compte. Par exemple si:</p>
<pre>
N = 100
h1(k)=1113
</pre>
<p>alors l&rsquo;index est 13. On n&rsquo;utilise pas les deux premiers chiffres 11.</p>
<p>Donc on peut utiliser la partie entière de la division <code class="codecolorer text default"><span class="text">h1(k) / N</span></code> comme seconde valeur de hachage.</p>
<p><strong><em>Et maintenant, à vos claviers!</em></strong></p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Faire dodo en C</title>
		<link>https://blog.developpez.com/dodo/p11170/langage/faire_dodo_en_c</link>
		<comments>https://blog.developpez.com/dodo/p11170/langage/faire_dodo_en_c#comments</comments>
		<pubDate>Fri, 20 Jul 2012 19:50:00 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Langage]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le langage C est réputé proche de la machine. Comme le langage dodo utilise des techniques très bas niveau, on pourrait penser que C serait une plate-forme idéale pour une implémentation efficace. La réalité n&#8217;est pas si simple. Il y a une fondamentale différence entre la façon dont dodo structure le code et C structure le code. C est un langage procédural, l&#8217;unité d&#8217;organisation du code est la fonction. De son côté dodo se base [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Le langage C est réputé proche de la machine. Comme le langage dodo utilise des techniques très bas niveau, on pourrait penser que C serait une plate-forme idéale pour une implémentation efficace. </p>
<p>La réalité n&rsquo;est pas si simple.<br />
 <span id="more-9"></span><br />
Il y a une fondamentale différence entre la façon dont dodo structure le code et C structure le code. C est un langage procédural, l&rsquo;unité d&rsquo;organisation du code est la fonction. De son côté dodo se base sur les continuations. </p>
<p>Nous l&rsquo;avons vu dans un article précédent, il est possible de simuler les continuations avec des fonctions à l&rsquo;aide de <a href="http://blog.developpez.com/dodo/p9236/technique/vers-une-premiere-implementation-de-dodo/">la boucle de continuations</a>. </p>
<p>Mais C y met un autre obstacle: il n&rsquo;offre pas de closures. Le rôle des closures est de capturer les variables qui doivent être encore utilisées par la suite. Les fonctions de Clojure font office de closures, ce qui m&rsquo;a permis d&rsquo;<a href="http://blog.developpez.com/dodo/p9400/langage/dodo/venez-jouer-1/">écrire une première implémentation</a> (dodo0). En C il faut mettre en place un autre mécanisme pour préserver les données qui doivent être réutilisées dans d&rsquo;autres continuations. </p>
<p>Mon idée est de faire correspondre une fonction dodo à une fonction C. Puisque les variables d&rsquo;une fonction sont généralement utilisées tout au long de son exécution, on peut les préserver au niveau d&rsquo;une fonction. </p>
<p>Une continuation est l&rsquo;équivalent d&rsquo;un GOTO, et en C la directive switch est aussi équivalente à GOTO. Alors chaque fonction a une boucle avec un switch pour aller d&rsquo;une continuation à l&rsquo;autre.</p>
<p>Mais il faut aussi pouvoir appeler d&rsquo;autres fonctions dodo, qui s&rsquo;attendent à une continuation de retour. Pour cela chaque fonction C a une fonction auxiliaire qui se charge de sauter directement à la continuation désignée lors de son appel.</p>
<p>J&rsquo;ai trouvé que dans certaines circonstances il était possible de faire tout cela sans allocation de mémoire, uniquement sur la pile! C&rsquo;est une bonne nouvelle.</p>
<p>Dans un prochain épisode, je donnerai plus de détails et des exemples de code. A bientôt!</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>La gestion d&#8217;exception de dodo en action</title>
		<link>https://blog.developpez.com/dodo/p9311/intro/la_gestion_d_exception_de_dodo_en_action</link>
		<comments>https://blog.developpez.com/dodo/p9311/intro/la_gestion_d_exception_de_dodo_en_action#comments</comments>
		<pubDate>Thu, 23 Sep 2010 02:09:14 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Intro]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Pour introduire le système d&#8217;exceptions de dodo (je préfère parler d&#8217;événements) je propose de s&#8217;atteler à une tâche simple, la traduction d&#8217;une méthode Java gérant les exceptions dans le langage dodo. Sans plus d&#8217;ambages, voici la méthode en question: private void openStore() { try { store = RecordStore.openRecordStore("CALCULATOR", true); for (int recordId = 1, last = store.getNextRecordID(); recordId &#60; last; recordId++) { byte[] record = null; try { record = store.getRecord(recordId); } catch (InvalidRecordIDException x) [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Pour introduire le système d&rsquo;exceptions de dodo (je préfère parler d&rsquo;<em>événements</em>) je propose de s&rsquo;atteler à une tâche simple, la traduction d&rsquo;une méthode Java gérant les exceptions dans le langage dodo.</p>
<p>Sans plus d&rsquo;ambages, voici la méthode en question:</p>
<pre>private void openStore() {
    try {
        store = RecordStore.openRecordStore("CALCULATOR", true);
        for (int recordId = 1, last = store.getNextRecordID(); recordId &lt; last; recordId++) {
            byte[] record = null;
            try {
                record = store.getRecord(recordId);
            } catch (InvalidRecordIDException x) {
                // record was deleted
            }
            if (record == null) {
                continue;
            }
            Statement stmt = new Statement(recordId, record);
            try {
                Compiler compiler = new Compiler(stmt.text);
                Compiler.Expression expr = compiler.compile();
                if (expr instanceof Compiler.Declaration) {
                    ((Compiler.Declaration)expr).declare(bindings);
                }
                stmt.state = Statement.COMPILED;
            } catch (CompileError x) {
                stmt.state = Statement.ERROR;
            }

            statements.addElement(stmt);
        }
    } catch(Exception x) {
    }
}
</pre>
<p><span id="more-4"></span><br />
On note trois blocs <code class="codecolorer text default"><span class="text">try</span></code>, le plus extérieur d&rsquo;entre eux se bornant à avaler toutes les exceptions qui pourraient échapper la partie intérieure.</p>
<p>Commençons par créer une méthode dodo. Cette méthode a des effets de bord, on ne peut donc pas recourir à la création d&rsquo;une fonction ordinaire.</p>
<p>Pour mémoire une méthode dodo commence par <code class="codecolorer text default"><span class="text">method</span></code>, suivi de son nom qui doit commencer en majuscule car l&rsquo;on déclare un nouveau type. Dans notre cas on n&rsquo;a pas besoin de variables ou de fonctions auxiliaires, alors le constructeur n&rsquo;est pas défini dans le bloc de la méthode.</p>
<p>On écrit donc:</p>
<pre>method OpenStore()
{
    ...
}
</pre>
<p>Maintenant écrivons le corps de la méthode. En première approximation nous allons essayer de reproduire exactement le code Java.</p>
<pre>method OpenStore()
{
    try {
        .store = RecordStore.OpenRecordStore("CALCULATOR", true)
        loop for (int recordId, last = (1, store.getNextRecord);
                  recordId &lt; last; ++.recordId) {
            byte[] record = null
            try {
                .record = store.getRecord(recordId)
            }
    ...
}
</pre>
<p>Pour affecter une valeur à la variable store, il faut en prendre sa référence; cela est marqué par un point devant son nom. Dans un effort pour réduire le nombre de noms réservés en dodo, toutes les boucles commencent par <code class="codecolorer text default"><span class="text">loop</span></code>.<br />
<br />
<hr />
<p></p>
<p>À ce point on arrive au premier bloc <code class="codecolorer text default"><span class="text">catch</span></code> du programme. Mais dodo n&rsquo;autorise pas à écrire un bloc <code class="codecolorer text default"><span class="text">catch</span></code> à l&rsquo;intérieur d&rsquo;un autre bloc. Comment traduire le programme en dodo?</p>
<p>Regardons encore ce que fait le bloc catch en question dans le programme original:</p>
<pre>            } catch (InvalidRecordIDException x) {
                // record was deleted
            }
</pre>
<p>Ce bloc ne fait rien, il se contente d&rsquo;avaler silencieusement une exception InvalidRecordIDException. En assumant que <code class="codecolorer text default"><span class="text">getRecord</span></code> ne jette pas une exception différente, on peut considérer tout ce qui suit comme faisant part d&rsquo;un bloc <code class="codecolorer text default"><span class="text">finally</span></code>.</p>
<p>Cela tombe bien, en dodo ce qui suit un bloc <code class="codecolorer text default"><span class="text">try</span></code> est l&rsquo;équivalent d&rsquo;un bloc <code class="codecolorer text default"><span class="text">finally</span></code>. Donc on peut continuer en ignorant le bloc <code class="codecolorer text default"><span class="text">catch</span></code>:</p>
<pre>method OpenStore()
{
    try {
        .store = RecordStore.OpenRecordStore("CALCULATOR", true)
        loop for (int recordId, last = (1, store.getNextRecord);
                  recordId &lt; last; ++.recordId) {
            byte[] record = null
            try {
                .record = store.getRecord(recordId)
            }
            case if (record = null) {
                continue()
            }
            def stmt = Statement(recordId, record)
    ...
}
</pre>
<p>Ici on construit un nouveau <em>Statement</em> avec les paramètres de constructeur <em>(recordId, record)</em>. Notez que l&rsquo;on utilise pas <code class="codecolorer text default"><span class="text">new</span></code> devant un constructeur. C&rsquo;est ce qui permet aux méthodes d&rsquo;être appelées comme des fonctions ordinaires, même si elles sont déclarées comme des types. De plus je n&rsquo;ai pas spécifié le type de <code class="codecolorer text default"><span class="text">stmt</span></code>. Si ce type correspond au type de retour de l&rsquo;expression, il suffit d&rsquo;utiliser &laquo;&nbsp;<code class="codecolorer text default"><span class="text">def</span></code>&nbsp;&raquo; et dodo se charge de donner le type approprié à la variable.</p>
<p>On arrive maintenant à un nouveau bloc <code class="codecolorer text default"><span class="text">try</span></code>. Cela ne devrait pas poser de difficulté particulière:</p>
<pre>method OpenStore()
{
    try {
        .store = RecordStore.OpenRecordStore("CALCULATOR", true)
        loop for (int recordId, last = (1, store.getNextRecord); 
                  recordId &lt; last; ++.recordId) {
            byte[] record = null
            try {
                .record = store.getRecord(recordId)
            }
            case if (record = null) {
                continue()
            }
            def stmt = Statement(recordId, record)
            try {
                def compiler = Compiler(stmt.text)
                def expr = compiler.compile
                case if (expr ~ ?Compiler.Declaration):
                    expr.Declare(bindings).
                .stmt.state = Statement.compiled
            }
    ...
}
</pre>
<p>On retrouve à nouveau le motif <code class="codecolorer text default"><span class="text">def variable = Constructeur(...)</span></code>, une notation à la simplicité bienvenue par rapport à Java. Le mot-clef <code class="codecolorer text default"><span class="text">case</span></code> est utilisé pour tous les branchements conditionnels comme <code class="codecolorer text default"><span class="text">loop</span></code> pour les boucles. Dodo a aussi la forme <code class="codecolorer text default"><span class="text">if ( ) ... else</span></code> mais elle ne s&rsquo;utilise que pour les expressions, l&rsquo;équivalent de <code class="codecolorer text default"><span class="text">( )? ... :</span></code> en Java.</p>
<p>Le test du type de la variable se fait par correspondance de patron (<em>pattern matching</em>), où le patron est ici introduit par &laquo;&nbsp;<code class="codecolorer text default"><span class="text">?</span></code>&nbsp;&raquo; suivi du nom du type. On peut aussi insérer d&rsquo;autres critères avant le point d&rsquo;interrogation, par exemple pour tester la valeur d&rsquo;un attribut de la variable.<br />
<br />
<hr />
<p></p>
<p>Nous voici donc à nouveau devant un bloc <code class="codecolorer text default"><span class="text">catch</span></code> qui suit un bloc <code class="codecolorer text default"><span class="text">try</span></code>. Cette fois-ci peut-on l&rsquo;ignorer comme s&rsquo;il n&rsquo;existait pas? Pas vraiment, cette fois-ci le bloc contient une instruction. Mais comme on arrive à la fin de la fonction il est peut-être raisonnable de décaler le bloc <code class="codecolorer text default"><span class="text">catch</span></code> un peu plus bas, en-dehors des autres blocs. Voici ce que cela donne:</p>
<pre>method OpenStore()
{
    try {
        .store = RecordStore.OpenRecordStore("CALCULATOR", true)
        loop for (int recordId, last = (1, store.getNextRecord);
                  recordId &lt; last; ++.recordId) {
            byte[] record = null
            try {
                .record = store.getRecord(recordId)
            }
            case if (record = null) {
                continue()
            }
            def stmt = Statement(recordId, record)
            try {
                def compiler = Compiler(stmt.text)
                def expr = compiler.compile
                case if (expr ~ ?Compiler.Declaration):
                    expr.Declare(bindings).
                .stmt.state = Statement.compiled
            }
            statements.AddElement(stmt)
        }
    }
    catch (event: ?CompileError) {
        .stmt.state = Statement.error
    }
    ...
}
</pre>
<p>L&rsquo;exception est comparée au patron fourni à <code class="codecolorer text default"><span class="text">catch</span></code>, et si elle correspond le bloc est exécuté.</p>
<p>On voit un problème ici: l&rsquo;instruction du <code class="codecolorer text default"><span class="text">catch</span></code> fait appel à la variable <code class="codecolorer text default"><span class="text">stmt</span></code>, qui n&rsquo;est pas déclarée au plus haut niveau de la méthode. Mais dodo ne s&rsquo;en formalise pas; si l&rsquo;exception se produit là où la variable <code class="codecolorer text default"><span class="text">stmt</span></code> est déclarée, alors l&rsquo;instruction est valide. Ailleurs l&rsquo;instruction produit une nouvelle exception. Si nécessaire, on peut restreindre le bloc <code class="codecolorer text default"><span class="text">catch</span></code> aux exceptions jetées après une étiquette de notre choix ce qui permet d&rsquo;éviter les variables non déclarées.<br />
<br />
<hr />
<p></p>
<p>Il ne manque plus qu&rsquo;à ajouter le bloc <code class="codecolorer text default"><span class="text">catch</span></code> du <code class="codecolorer text default"><span class="text">try</span></code> englobant qui avale toutes les exceptions. On obtient:</p>
<pre>method OpenStore()
{
    try {
        .store = RecordStore.OpenRecordStore("CALCULATOR", true)
        loop for (int recordId, last = (1, store.getNextRecord);
                  recordId &lt; last; ++.recordId) {
            byte[] record = null
            try {
                .record = store.getRecord(recordId)
            }
            case if (record = null) {
                continue()
            }
            def stmt = Statement(recordId, record)
            try {
                def compiler = Compiler(stmt.text)
                def expr = compiler.compile
                case if (expr ~ ?Compiler.Declaration):
                    expr.Declare(bindings).
                .stmt.state = Statement.compiled
            }
            statements.AddElement(stmt)
        }
    }
    catch (event: ?CompileError) {
        .stmt.state = Statement.error
    }
    catch {
    }
}
</pre>
<p>Certes ce programme correspond bien au programme Java initial, mais l&rsquo;on a pas profité de toutes les possibilités de dodo en terme de gestion d&rsquo;exception. Pour commencer, à quoi bon écrire un bloc <code class="codecolorer text default"><span class="text">try</span></code> si il n&rsquo;y a pas d&rsquo;instructions à exécuter par la suite? Puisqu&rsquo;un bloc <code class="codecolorer text default"><span class="text">catch</span></code> n&rsquo;est pas attaché à un bloc <code class="codecolorer text default"><span class="text">try</span></code> particulier, la gestion d&rsquo;exception intervient même s&rsquo;il n&rsquo;y a pas de <code class="codecolorer text default"><span class="text">try</span></code>. Enlevons donc ce bloc <code class="codecolorer text default"><span class="text">try</span></code> superflu:</p>
<pre>method OpenStore()
{
    .store = RecordStore.OpenRecordStore("CALCULATOR", true)
    loop for (int recordId, last = (1, store.getNextRecord); 
              recordId &lt; last; ++.recordId) {
        byte[] record = null
        try {
            .record = store.getRecord(recordId)
        }
        case if (record = null) {
            continue()
        }
        def stmt = Statement(recordId, record)
        try {
            def compiler = Compiler(stmt.text)
            def expr = compiler.compile
            case if (expr ~ ?Compiler.Declaration):
                expr.Declare(bindings).
            .stmt.state = Statement.compiled
        }
        statements.AddElement(stmt)
    }
    catch (event: ?CompileError) {
        .stmt.state = Statement.error
    }
    catch {
    }
}
</pre>
<p>Ensuite on voit là un motif intéressant:</p>
<pre>        def stmt = Statement(recordId, record)
        try {
            ...
        }
        statements.AddElement(stmt)
</pre>
<p>Ici on initialise la variable <code class="codecolorer text default"><span class="text">stmt</span></code>, on exécute un bloc <code class="codecolorer text default"><span class="text">try</span></code>, puis finalement on ajoute la variable à une liste à l&rsquo;aide d&rsquo;une seule instruction. Cette dernière s&rsquo;exécute aussi bien en cas de succès qu&rsquo;en cas d&rsquo;exception.<br />
<br />
<hr />
<p></p>
<p>Dodo propose une notation spéciale pour ce motif qui rend le programme plus succinct. L&rsquo;instruction finale remonte au niveau de l&rsquo;instruction d&rsquo;initialisation, et tout ce qui suit fait partie d&rsquo;un bloc <code class="codecolorer text default"><span class="text">try</span></code> implicite. Je l&rsquo;utilise dans le programme ci-dessous.</p>
<pre>method OpenStore()
{
    .store = RecordStore.OpenRecordStore("CALCULATOR", true)
    loop for (int recordId, last = (1, store.getNextRecord);
              recordId &lt; last; ++.recordId) {
        byte[] record = null
        try {
            .record = store.getRecord(recordId)
        }
        case if (record = null) {
            continue()
        }
        def stmt = Statement(recordId, record) ...&gt; statements.AddElement(stmt)
        def compiler = Compiler(stmt.text)
        def expr = compiler.compile
        case if (expr ~ ?Compiler.Declaration):
            expr.Declare(bindings).
        .stmt.state = Statement.compiled
    }
    catch (event: ?CompileError) {
        .stmt.state = Statement.error
    }
    catch {
    }
}
</pre>
<p>Enfin, on peut se débarrasser du dernier <code class="codecolorer text default"><span class="text">try</span></code> en remarquant que le <code class="codecolorer text default"><span class="text">continue</span></code> ne s&rsquo;exécute que si <code class="codecolorer text default"><span class="text">getRecord</span></code> a jeté une exception, auquel cas un bloc <code class="codecolorer text default"><span class="text">catch</span></code> peut intervenir. Au lieu de placer un <code class="codecolorer text default"><span class="text">continue</span></code> dans ce bloc <code class="codecolorer text default"><span class="text">catch</span></code>, je vais utiliser <code class="codecolorer text default"><span class="text">resume</span></code> avec une étiquette judicieusement placée pour passer à l&rsquo;itération suivante de la boucle.</p>
<pre>method OpenStore()
{
    .store = RecordStore.OpenRecordStore("CALCULATOR", true)
    loop for (int recordId, last = (1, store.getNextRecord);
              @cond recordId &lt; last; ++.recordId) {
        def record = store.getRecord(recordId)
        def stmt = Statement(recordId, record) ...&gt; statements.AddElement(stmt)
        def compiler = Compiler(stmt.text)
        def expr = compiler.compile
        case if (expr ~ ?Compiler.Declaration):
            expr.Declare(bindings).
        .stmt.state = Statement.compiled
    }
    catch (event: ?InvalidRecordIDException) {    # record was deleted
        ++.recordId
        resume @cond
    }
    catch (event: ?CompileError) {
        .stmt.state = Statement.error
    }
    catch {
    }
}
</pre>
<p>En obligeant les blocs <code class="codecolorer text default"><span class="text">catch</span></code> à se situer en-dehors des autres blocs, et à l&rsquo;aide d&rsquo;autres astuces de notation, dodo permet d&rsquo;écrire des instructions qui ne se mélangent pas avec la gestion des cas exceptionnels. Le programme y gagne en clarté et en concision.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Monsieur Curry</title>
		<link>https://blog.developpez.com/dodo/p9340/technique/monsieur_curry</link>
		<comments>https://blog.developpez.com/dodo/p9340/technique/monsieur_curry#comments</comments>
		<pubDate>Fri, 01 Oct 2010 22:45:19 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Flânerie]]></category>
		<category><![CDATA[Technique]]></category>
		<category><![CDATA[Théorie]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Mr Haskell Curry est un logicien qui a donné son nom à une technique utilisée en programmation fonctionnelle, le currying. Celle-ci a pour origine les travaux de Gottlob Frege et Moses Schönfinkel, ce qui a poussé Christopher Strachey à suggérer le nom de schönfikelisation en tant qu&#8217;alternative. Ne nous attardons pas plus longtemps sur les détails triviaux. Voyons ce que le terme signifie en informatique. Le currying transforme une fonction qui s&#8217;applique à une liste [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Mr Haskell Curry est un logicien qui a donné son nom à une technique utilisée en programmation fonctionnelle, le <em>currying</em>. Celle-ci a pour origine les travaux de Gottlob Frege et Moses Schönfinkel, ce qui a poussé Christopher Strachey à suggérer le nom de <em>schönfikelisation</em> en tant qu&rsquo;alternative.</p>
<p>Ne nous attardons pas plus longtemps sur les détails triviaux. Voyons ce que le terme signifie en informatique.<br />
<span id="more-26"></span><br />
Le currying transforme une fonction qui s&rsquo;applique à une liste de paramètres:</p>
<pre>f(x, y, z)
</pre>
<p>en une fonction qui s&rsquo;applique à un seul paramètre, qui retourne une autre fonction à un paramètre, etc jusqu&rsquo;à consommer tous les paramètres.</p>
<pre>f(x) -> f'(y) -> f''(z)
</pre>
<p>En dodo cette transformation se fait en remplaçant les paramètres de la fonction avec des caractères de soulignement _.</p>
<pre>def g = f(_, _, _)
</pre>
<p>On peut appeler cette fonction avec trois paramètres de la façon suivante:</p>
<pre>g(1)(3)(n) 	# = f(1, 3, n)
</pre>
<p>Quel est l&rsquo;avantage de faire cela? Et bien cela permet d&rsquo;appeler <code class="codecolorer text default"><span class="text">g</span></code> avec un seul ou deux paramètres, et réutiliser la fonction résultante comme une fonction ordinaire. Dans un langage qui n&rsquo;utilise que les fonctions curriées cela donne des propriétés intéressantes.</p>
<p>Dodo n&rsquo;est pas un tel langage mais l&rsquo;option est là.<br />
Une autre utilisation du caractère de soulignement est d&rsquo;appeler une fonction avec des paramètres renseignés à l&rsquo;avance, par exemple:</p>
<pre>def normalise = min(_, 100)
.x = normalise(x)	# contraint x à être inférieur ou égal à 100
</pre>
<p>Cela peut aussi servir à composer des fonctions:</p>
<pre>def positive_sinus = abs(_) &#038; sin(_)
positive_sinus(-0.5)	# = sin(abs(-0.5))
</pre>
<p>Ici &laquo;&nbsp;<code class="codecolorer text default"><span class="text">&amp;</span></code>&nbsp;&raquo; sert à combiner les deux fonctions en une nouvelle fonction, qui les applique dans l&rsquo;ordre à l&rsquo;argument. Cela ne marche pas avec les fonctions ordinaires, il faut utiliser _.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Commentaire sur la gestion d&#8217;exception</title>
		<link>https://blog.developpez.com/dodo/p9319/technique/commentaire_sur_la_gestion_d_exception</link>
		<comments>https://blog.developpez.com/dodo/p9319/technique/commentaire_sur_la_gestion_d_exception#comments</comments>
		<pubDate>Fri, 24 Sep 2010 12:46:06 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le dernier ticket sur la gestion d&#8217;exception (ou d&#8217;événement), malgré sa longueur, ne décrit pas un aspect délicat de celui-ci: la gestion d&#8217;exception dans les instructions de finalisation. En effet, si les instructions d&#8217;un bloc try ont terminé sur le retour de la fonction (return) ou sur une exception non capturée, il reste toujours des instructions de finalisation a exécuter. D&#8217;autres langages comme Java ont des règles peu satisfaisantes en ce qui concerne les exceptions [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Le dernier ticket <a href="/dodo/p9311/intro/la-gestion-d-exception-de-dodo-en-action/">sur la gestion d&rsquo;exception</a> (ou <em>d&rsquo;événement</em>), malgré sa longueur, ne décrit pas un aspect délicat de celui-ci: la gestion d&rsquo;exception dans les instructions de finalisation. En effet, si les instructions d&rsquo;un bloc <code class="codecolorer text default"><span class="text">try</span></code> ont terminé sur le retour de la fonction (<code class="codecolorer text default"><span class="text">return</span></code>) ou sur une exception non capturée, il reste toujours des instructions de finalisation a exécuter. D&rsquo;autres langages comme Java ont des règles peu satisfaisantes en ce qui concerne les exceptions levées à ce moment-là.<br />
<span id="more-8"></span><br />
Pour comprendre la perspective de dodo sur ce point, il faut se rappeler un fait auquel je faisais allusion dans le dernier article: <em>en dodo ce qui suit un bloc <code class="codecolorer text default"><span class="text">try</span></code> est l&rsquo;équivalent d&rsquo;un bloc <code class="codecolorer text default"><span class="text">finally</span></code></em>.</p>
<p>Voyons quelques scénarios possibles:</p>
<pre>
A.
  try {
    throw ExceptionA()
  }
  throw OtherException()

B.
  try {
    return x
  }
  throw ExceptionB()

C.
  try {
    throw ExceptionC()
  }
  return y
</pre>
<p><strong>A. Masquage d&rsquo;exception</strong></p>
<p>Dans le cas A, les instructions de finalisation jettent une autre exception après que le bloc <code class="codecolorer text default"><span class="text">try</span></code> ait déjà fait de même. Dans ce cas les instructions de finalisation s&rsquo;interrompent et la fonction jette une exception. En Java, l&rsquo;exception jetée serait <em>OtherException</em> mais ce n&rsquo;est pas une bonne solution. En effet, l&rsquo;important est avant tout ce qui est arrivé auparavant à l&rsquo;intérieur du bloc <code class="codecolorer text default"><span class="text">try</span></code>. Dodo, pour sa part, retourne l&rsquo;exception <em>ExceptionA</em>. Mais ce n&rsquo;est que le premier événement de la chaîne d&rsquo;événements et l&rsquo;on peut aussi obtenir la valeur de <em>OtherException</em> dans le code appelant.</p>
<p>Voici un résumé de l&rsquo;exécution:</p>
<pre>
1.  try {
2.    throw ExceptionA()
</pre>
<p>Ici le contrôle échappe du bloc try, et continue dans les instructions de finalisation:</p>
<pre>3.  throw OtherException()
</pre>
<p>Maintenant les instructions de finalisation ne peuvent plus continuer.<br />
La fonction termine avec une exception, retournant la chaîne d&rsquo;événements:</p>
<pre>  ExceptionA, OtherException.
</pre>
<p>Le code appelant voit <em>ExceptionA</em> en tête de la chaîne d&rsquo;événements.</p>
<p><strong>B. Exception piégée par un return</strong></p>
<p>Dans le cas B, le bloc <code class="codecolorer text default"><span class="text">try</span></code> termine en retournant une valeur <em>x</em>. Dans ce cas on pourrait argumenter que l&rsquo;exception levée dans les instructions de finalisation est plus importante que la valeur de retour, mais ce n&rsquo;est pas l&rsquo;approche de dodo. En dodo, l&rsquo;exécution des instructions de finalisation s&rsquo;interrompt à l&rsquo;exception et la fonction retourne la valeur <em>x</em>. Cependant, lors de la compilation il y a un message d&rsquo;avertissement si les exceptions levées par le code de finalisation ne sont pas gérées dans un bloc <code class="codecolorer text default"><span class="text">catch</span></code> alors que le bloc <code class="codecolorer text default"><span class="text">try</span></code> contient un <code class="codecolorer text default"><span class="text">return</span></code>.</p>
<p>Pour éviter l&rsquo;avertissement il faut gérer les cas exceptionnels dans les instructions de finalisation. Notez tout de même que dodo ne permet pas d&rsquo;altérer le résultat final, qui est le retour de <em>x</em> à la fin de la fonction.</p>
<p>Un résumé de l&rsquo;exécution pour cas B:</p>
<pre>
1.  try {
2.    return x
</pre>
<p>Ici le contrôle échappe du bloc try, et continue dans les instructions de finalisation:</p>
<pre>3.  throw ExceptionB()
</pre>
<p>Maintenant les instructions de finalisation ne peuvent plus continuer.<br />
Cependant le résultat de la fonction était déjà décidé avant, lorsque <code class="codecolorer text default"><span class="text">return</span></code> a été appelé.<br />
L&rsquo;exception <em>ExceptionB</em> ne sort donc pas de la fonction. On dit qu&rsquo;elle est piégée.</p>
<p><strong>C. Instruction return tardive</strong></p>
<p>Dans le cas C, les instructions de finalisation appellent <code class="codecolorer text default"><span class="text">return</span></code> alors qu&rsquo;une exception a été levée avant:</p>
<pre>  try {
    throw ExceptionC()
  }
  return y
</pre>
<p>L&rsquo;exception gagne, et la fonction termine en exception. Mais la valeur de retour est ajoutée à la chaîne d&rsquo;événements. Le code appelant voit donc:</p>
<pre>  ExceptionC, return(y).
</pre>
<p>On peut aussi envisager un cas D où le bloc <code class="codecolorer text default"><span class="text">try</span></code> et le code de finalisation tous deux retournent une valeur. Dans ce cas la première valeur est retournée et le second <code class="codecolorer text default"><span class="text">return</span></code> est piégé. Cela ne génère pas de message d&rsquo;avertissement, bien que ce soit bien entendu peu recommandé.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>La transformation du if</title>
		<link>https://blog.developpez.com/dodo/p9273/langage/la_transformation_du_if</link>
		<comments>https://blog.developpez.com/dodo/p9273/langage/la_transformation_du_if#comments</comments>
		<pubDate>Fri, 10 Sep 2010 13:54:43 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Langage]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[La construction if (condition) ... else ... se retrouve dans pratiquement tous les langages de programmation. Suivant la valeur de vérité de la condition (vrai ou faux), le premier résultat est retourné ou bien le second. Que se passe-t-il dans un exemple simple? Prenons le code suivant: def f(n) = if (n &#60; 7) 1 + f(n+1) else n Dodo est basé sur le passage de continuations. Ici les deux continuations pour le if sont: [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>La construction <code class="codecolorer text default"><span class="text">if (condition) ... else ...</span></code> se retrouve dans pratiquement tous les langages de programmation. Suivant la valeur de vérité de la condition (vrai ou faux), le premier résultat est retourné ou bien le second.</p>
<p>Que se passe-t-il dans un exemple simple?<br />
<span id="more-5"></span><br />
Prenons le code suivant:</p>
<pre>
   def f(n) =
      if (n &lt; 7)
         1 + f(n+1)
      else
         n
</pre>
<p>Dodo est basé sur le passage de continuations. Ici les deux continuations pour le <code class="codecolorer text default"><span class="text">if</span></code> sont:</p>
<pre>
   1 + f(n+1)
</pre>
<p>et</p>
<pre>
   n
</pre>
<p>Donc l&rsquo;instruction if&#8230; else&#8230; doit examiner la condition (n &lt; 7), et en fonction de son résultat choisir la continuation qui correspond.</p>
<p>La logique s&#039;apparente à:</p>
<pre>
   # Calculer la valeur de vérité
   n  résultat
   # Choisir une continuation
   match(résultat, true) -&gt;
      1 + f(n+1)
   |
      n;;
</pre>
<p>Mais on peut faire mieux. Imaginons que l&rsquo;opération de comparaison <code class="codecolorer text default"><span class="text">&amp;lt;</span></code> ne retourne pas une valeur de vérité, mais plutôt choisit une continuation. Transformer cela en valeur de vérité revient à:</p>
<pre>
   n 
      true
   |
      false;
</pre>
<p>Voyez-vous où j&rsquo;en viens? Pour la construction if&#8230; else&#8230; il suffit de remplacer les continuations dans l&rsquo;expression ci-dessus. Soit:</p>
<pre>
   n 
      1 + f(n+1)
   |
      n;
</pre>
<p>La construction <code class="codecolorer text default"><span class="text">if (a &amp;lt; b) ... else ...</span></code> peut être traduit en forme avec continuations par une simple transformation, comme décrit ci-dessus.</p>
<p>Je vais appeler la fonction qui correspond à l&#039;opérateur <code class="codecolorer text default"><span class="text">&amp;lt;</span></code>, &quot;lessThan&quot;. Le type de la fonction classique pour les entiers est:</p>
<pre>
   Fun(int,int-&gt;bool)
</pre>
<p>Le type de la fonction basée sur les continuations est en dodo:</p>
<pre>
   Fun(int,int-&gt;(),())
</pre>
<p>Et on pourrait l&rsquo;écrire un peu comme:</p>
<pre>
   def lessThan = fun (int a, b) -&gt; yes(), no()
   {
      {- Code pseudo-assembleur -
         COMPARE(a,b)
         IFNEGATIVE yes()
         no()
      -}
   }
</pre>
<p>C&rsquo;est simple et efficace.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Vers une première implémentation de dodo: la boucle de continuations</title>
		<link>https://blog.developpez.com/dodo/p9236/langage/vers_une_premiere_implementation_de_dodo</link>
		<comments>https://blog.developpez.com/dodo/p9236/langage/vers_une_premiere_implementation_de_dodo#comments</comments>
		<pubDate>Thu, 26 Aug 2010 00:43:23 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Intro]]></category>
		<category><![CDATA[Langage]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Le projet dodo a commencé il y a bien longtemps, et l&#8217;idée de mettre ses concepts en pratique me trottait dans la tête depuis un bon moment. Malheureusement je ne voyais pas clairement comment m&#8217;y prendre. Eh bien grâce à une suggestion que l&#8217;on m&#8217;a faite, il semble que j&#8217;aie finalement la solution. Pour pouvoir exécuter un programme dodo, le plus simple serait probablement d&#8217;écrire un interpréteur. Cependant j&#8217;anticipais des difficultés certaines avec cette approche [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Le projet dodo a commencé il y a bien longtemps, et l&rsquo;idée de mettre ses concepts en pratique me trottait dans la tête depuis un bon moment. Malheureusement je ne voyais pas clairement comment m&rsquo;y prendre.</p>
<p>Eh bien grâce à une suggestion que l&rsquo;on m&rsquo;a faite, il semble que j&rsquo;aie finalement la solution.<br />
<span id="more-7"></span><br />
Pour pouvoir exécuter un programme dodo, le plus simple serait probablement d&rsquo;écrire un interpréteur. Cependant j&rsquo;anticipais des difficultés certaines avec cette approche et comme il faudra de toute façon écrire un jour un compilateur pour questions de performance, le jeu n&rsquo;en vaut pas la chandelle.</p>
<p>Donc je voulais écrire un compilateur. Celui-ci va prendre en entrée un programme dodo, et produire en sortie un programme que l&rsquo;ordinateur peut exécuter. L&rsquo;ordinateur exécute les instructions en langage machine, mais on passe généralement par l&rsquo;<em>assembleur</em> pour le générer. Très bien. Seulement je ne suis pas exactement confortable avec l&rsquo;assembleur; la recherche d&rsquo;un expert pour m&rsquo;aider s&rsquo;est conclue en rentrée bredouille.</p>
<p>Il y a d&rsquo;autres solutions. Par exemple, la <em>JVM</em> (le programme qui exécute Java) possède un assembleur simplifié, de même pour <em>LLVM</em>. Cependant ces assembleurs ont l&rsquo;inconvénient de ne pas offrir le GOTO. Certes, l&rsquo;instruction GOTO n&rsquo;est pas appropriée pour un langage de haut niveau qui se doit d&rsquo;être maintenable, mais son absence d&rsquo;un langage de très bas niveau comme un <em>assembleur</em> me chagrine.</p>
<p>J&rsquo;ai découvert que le langage <em>C</em>, dans la version étendue de <em>gcc</em>, permet le GOTO local à une procédure. J&rsquo;ai pu l&rsquo;utiliser pour traduire un petit programme &laquo;&nbsp;<a href="http://dodo.sourceforge.net/examples/HelloWorld.c.html">HelloWorld</a>&nbsp;&raquo; de dodo en C. Il semblait y avoir une possibilité de traduire automatiquement les programmes dodo en C et de les compiler grâce à <em>gcc</em>, ce qui me convenait bien. Cependant le GOTO de <em>gcc</em> est limité à 255 labels ce qui n&rsquo;est pas suffisant pour dodo.</p>
<p>Une autre idée est de remplacer le GOTO par un SWITCH, et en effet on peut aller plus loin de cette façon. Mais à ce point je me préoccupait déjà de la gestion de la mémoire pour les variables et cette approche n&rsquo;était pas des plus prometteuses.</p>
<p>C&rsquo;est alors qu&rsquo;en visite auprès de ma famille, un parent (merci Romain!) à qui je parlais de dodo m&rsquo;a suggéré les pointeurs de fonction. C&rsquo;était suffisant pour m&rsquo;orienter vers une nouvelle solution.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Timing du chargement des classes</title>
		<link>https://blog.developpez.com/dodo/p7942/technique/timing_du_chargement_des_classes</link>
		<comments>https://blog.developpez.com/dodo/p7942/technique/timing_du_chargement_des_classes#comments</comments>
		<pubDate>Tue, 11 Aug 2009 07:56:54 +0000</pubDate>
		<dc:creator><![CDATA[bredelet]]></dc:creator>
				<category><![CDATA[Dodo]]></category>
		<category><![CDATA[Technique]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Dans une fonction qui se veut libre d&#8217;effets de bord, certaines operations qui semblent anodines peuvent compromettre la propriété désirée de la fonction. Par exemple, le chargement d&#8217;une classe en mémoire. Quand dodo charge une classe en mémoire pour la première fois il crée normalement une instance de cette classe qui est utilisée comme prototype pour tous les objets de la classe. Si la classe comprend un constructeur sans paramètres, ce constructeur est utilisé. Mais [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Dans une fonction qui se veut libre d&rsquo;effets de bord, certaines operations qui semblent anodines peuvent compromettre la propriété désirée de la fonction. Par exemple, le chargement d&rsquo;une classe en mémoire.<br />
<span id="more-6"></span><br />
Quand dodo charge une classe en mémoire pour la première fois il crée normalement une instance de cette classe qui est utilisée comme prototype pour tous les objets de la classe. Si la classe comprend un constructeur sans paramètres, ce constructeur est utilisé. Mais un constructeur n&rsquo;est pas libre d&rsquo;effets de bord. Il peut faire des opérations qui sont visibles pour d&rsquo;autres parties du programme.</p>
<p>D&rsquo;un autre côté, même si un tel constructeur n&rsquo;est pas défini pour la classe, l&rsquo;initialisation d&rsquo;un attribut de l&rsquo;instance ou de la classe peut causer le chargement d&rsquo;une autre classe. Le chargement de cette autre classe n&rsquo;est pas toujours sans effets de bord.</p>
<p>Pour conserver la propriété &laquo;&nbsp;libre d&rsquo;effets de bord&nbsp;&raquo; de la fonction, il est nécessaire de charger la classe sans effets de bord. Cela signifie que si la classe en question possède un constructeur sans paramètres, ou que l&rsquo;une des classes utilisées par cette classe doit être chargée avec des effets de bord, la classe ne peut pas être complètement initialisée dans la contexte de la fonction.</p>
<p>En conséquence une fonction peut terminer en erreur simplement du fait qu&rsquo;elle déclare un objet d&rsquo;une classe qui n&rsquo;a pas été initialisée.</p>
<p>Pour éviter que cela n&rsquo;arrive il faut charger la classe en mémoire dans un constructeur appelé avant la fonction. Par exemple, il pourrait être le constructeur de la classe qui contient la fonction, ou le corps principal du programme ou d&rsquo;une librairie.</p>
]]></content:encoded>
			<wfw:commentRss></wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
