• Aucun résultat trouvé

HipHop.js et le temps : délai et instant

4 PENSER L’ORCHESTRATION PAR PATTERN ET AUTOMATE

5.1 Principe de la programmation réactive synchrone

5.2.2 HipHop.js et le temps : délai et instant

Nous avons beaucoup écrit sur le temps dans les précédents chapitres, et notamment sur la repré- sentation du temps avec les langages synchrones. Or il y a un terme fréquemment utilisé par les programmeurs HipHop.js qui n’est pas toujours facile de saisir, c’est le terme de délai. Dans le lan- gage commun, qui est celui des horloges, un délai est « le temps accordé pour faire quelque chose » (Dictionnaire Larousse). C’est aussi le temps (des horloges) compris entre deux événements. Le dé- lai de livraison est le temps qui s’écoule entre un engagement de livrer une marchandise et la date effective de livraison par exemple. Or le terme délai en programmation HipHop.js n’a pas exacte- ment ce sens. Il a un sens plus général qui rend possible une mise en œuvre de la notion de durée à la Bergson. Un délai en HipHop.js est un événement ou une conjonction d’évènements. Ces évè- nements peuvent relever du temps des horloges, mais pas nécessairement. Un délai peut être l’aboutissement d’un trajet, le résultat de l’action de quelqu’un dans une assistance… en fait tout ce qui peut s’exprimer au moyen d’un signal ou d’une combinaison logique de signaux. Nous sommes donc bien à un niveau d’abstraction au-dessus du temps des horloges, c’est ce qui rend HipHop.js apte à s’occuper des durées au sens de Bergson.

Nous nous sommes permis d’insister sur ce point car dans la littérature sur la programmation syn- chrone nous rencontrons fréquemment des explications faisant référence au temps, qui sont diffi- ciles à comprendre si l’on ne fait pas abstraction du temps des horloges. Parmi ces explications complexes il y a la différence entre délai standard, délai immédiat et délai compté. Ce que l’on appelle un délai standard, est l’occurrence d’un événement qui se traduit par la valeur logique « vrai » d’un signal ou le résultat « vrai » de l’évaluation d’une expression logique JavaScript ou HipHop.js. HipHop.js sera à l’écoute de cet événement dès qu’une instruction le concernant appa- raitra une première fois. Le programme sera à l’écoute, mais pour qu’il traite effectivement l’évè- nement une première fois, il faudra attendre une réaction de l’automate. En parler esterellien on dira « qu’un délai démarre quand une instruction temporelle qui le traite démarre, et il se finira dans un instant ultérieur ». La première réaction passée, le signal est traité à chaque réaction. Si l’on souhaite qu’un évènement soit traité dès la première réaction, sans attendre une réaction ul- térieure de l’automate, il faudra le qualifier « d’immédiat ». Un délai compté est simple à com- prendre, c’est le nombre de fois que l’occurrence d’un évènement a été comptée par une suite de réactions provoquées sur l’automate HipHop.js.

Un terme intéressant en parler esterellien est celui d’instant. L’instant de HipHop.js est un bon moyen de faciliter la mise en œuvre de la durée sous une forme inspirée de Bergson. Un instant, n’est pas une indication d’horloge mais bien une réaction provoquée sur l’automate HipHop.js qui peut provenir d’une conscience.

Nous pensons que cette petite mise au point permettra d’être plus à l’aise dans la lecture de la littérature sur Esterel ou HipHop.js, et notamment de rendre compréhensible une expression du type « Un délai immédiat peut s’écouler instantanément » qui dans le langage commun est diffici- lement compréhensible. En effet dans le langage commun, comment un délai peut-il être

58

immédiat ? Si immédiat signifie de « durée nulle », l’idée n’est pas facile à saisir car ce qui définit un délai c’est bien qu’il s’écoule un temps mesurable différent de zéro entre un début et une fin. Dans notre langage de tous les jours, s’il n’y a pas de temps qui s’écoule, il n’y a pas non plus de délai. Mais en fait cette phrase signifie que « l’occurrence d’un évènement, peut être prise en compte sans attendre que l’automate ait été activé une nouvelle fois ». On rencontre aussi l’ex- pression « terminaison d’un délai » qui est l’équivalent de « l’occurrence d’un évènement ». Voyons à présent un premier exemple de programme HipHop.js.

5.2.3 Les instructions HipHop.js

Le langage HipHop.js et son utilisation sont décrits dans la Thèse de Colin Vidal sur la Programma-

tion web réactive [87]. Depuis cette thèse, il y a eu des modifications mineures de la syntaxe. Les

instructions sont actuellement en minuscules. Les expressions sur les signaux ont changé de forme, plutôt que NOW(identifier) nous avons identifier.now, de même pour identifier.preval, ou identifier.val. Il y a aussi quelques changements sur le positionnement de parenthèses au lieu de AWAIT COUNT(3, NOW(s)), nous avons await count (3, s.now).

Si le compilateur HipHop.js a connu et connait encore des évolutions, la syntaxe est basée sur Este-

rel V5 et reste conforme à sa définition. Nous ne reprendrons donc pas ici la description complète

faite par Colin Vidal dans sa thèse ou celle de Gérard Berry dans le document The Esterel v5 Lan-

guage Primer [8]. Nous renvoyons le lecteur à ces deux ouvrages indispensables à tout program-

meurs HipHop.js. Nous procéderons plutôt par exemples de programmes développés pour notre plateforme. Voici un extrait d’un programme de contrôle d’une orchestration. Dans un premier temps nous ne nous focaliserons pas sur l’aspect musical de ce programme que nous aborderons dans les chapitres suivants, mais sur le langage HipHop.js.

1. hiphop module trajetModule3(in start, stop, tick, abletonON)

2. implements ${nuceraInt.creationInterfaces(par.groupesDesSons[2])} {

3. signal tempsNucera=0;

4. loop {

5. abort(stop.now) {

6. await immediate (start.now);

7. hop {

8. console.log("--Automate des possibles Nucera");

9. }

10. fork{

11. every immediate (tick.now) {

12. fork{ 13. hop { gcs.setTickOnControler(tempsNucera.nowval); } 14. }par{ 15. emit tempsNucera(tempsNucera.preval + 1); 16. } 17. } 18. }par{ 19. run usine(...); 20. run conscience(...); 21. run maladie(...); 22. run arretUsine(...); 23. run guerison(...); 24. } 25. }

26. hop { console.log("--Arret d'Automate des possibles Nucera");

27. ableton.cleanQueues();

28. oscMidiLocal.convertAndActivateClipAbleton(300);

29. // Commande d'arrêt global

30. }

59

32. }

33. }

34. exports.trajetModule3 = trajetModule3;

La première ligne introduit le module dont le nom est trajetModule3(). Il est déclaré avec 4 si- gnaux, start, stop, tick et abletonON. Le signal start est spécifiquement déclaré comme un signal entrant, les autres par défaut sont entrants et sortants, soit inout. La ligne 2 est un peu plus complexe, retenons pour le moment qu’il s’agit d’un autre moyen de déclarer des signaux traités par le module. En ligne 3, nous avons un signal local tempsNucera initialisé à 0. Local signifie que ce signal n’est pas vu en dehors du module. En ligne 4, nous rencontrons la première instruction du module : loop. Le corps du code délimité par les accolades suivant loop sera répété automatique- ment lorsque le déroulement séquentiel des instructions du corps sera arrivé au bout. Le corps à l’intérieur des accolades correspondant à loop{} peut être interrompu par l’instruction en ligne 5, abort. Cette instruction agit sur un corps délimité par des accolades de la même manière que

loop. La commande abort, interrompt le contenu de son corps quand le signal placé en paramètre est vrai, c’est-à-dire quand le signal stop a été émis par le programme principal et que celui-ci provoque une réaction. On évalue si le signal stop a été émis en utilisant la syntaxe stop.now. Avec la commande abort, la préemption est dite forte, c’est-à-dire que lorsque l’évènement stop se produit le corps du abort n’est pas exécuté. Si pour une raison quelconque nous avions souhaité que le corps du abort soit exécuté une dernière fois, lors de l’occurrence de l’évènement stop, nous aurions utilisé l’instruction weakabort. Dans ce cas nous disons que la préemption est faible. La première instruction dans le corps du abort est await. Tant que le signal start n’a pas été reçu, cette instruction bloque le thread dans son déroulement séquentiel en ligne 6. immediate signifie que nous avons décidé de prendre en compte le signal start au moment même où nous rencon- trons l’instruction await. Sans immediate ce n’est pas ce qui se produit. La première fois que dans un module HipHop.js nous rencontrons une instruction await sur un signal, le signal n’est pas éva- lué. Il le sera à chaque réaction suivante. Comme nous l’avons vu précédemment avec l’instruction

abort, si nous souhaitons évaluer un signal quand nous le rencontrons une première fois dans un

await, il faut le préciser avec l’instruction immediate.

En ligne 7 nous avons une instruction fort pratique, hop{}, qui permet d’insérer du code JavaScript directement à l’intérieur d’un module.

La ligne 10 introduit un des concepts phares de HipHop.js, le parallélisme. L’instruction fork{} va de pair avec l’instruction par{} pour « parallèle ». Chacune des instructions fork et par est suivie d’un corps entre accolade. Les deux corps sont exécutés en parallèle à chaque réaction. L’ensemble des instructions fork et par associées se termine quand l’ensemble des corps se terminent. Ici le

fork de la ligne 10 se terminera quand nous aurons atteint la ligne 17 et la ligne 24.

En ligne 11, nous rencontrons l’instruction every{}. Le corps d’un every est sollicité à chaque oc- currence de l’évènement en paramètre, ici tick.now. Comme pour await, nous devons ajouter

immediate si nous souhaitons activer every dès la première fois que nous rencontrons tick.now. La prochaine nouveauté est en ligne 15, avec la commande emit. Il s’agit de l’émission d’un signal, ici tempsNucera auquel nous assignons une valeur tempsNucera.preval + 1. L’émission d’un signal peut être vue comme une diffusion (broadcast) de ce signal à l’intérieur du programme Hi- pHop.js. Ici, le signal tempsNucera n’est pas réutilisé à l’intérieur de ce module, mais il pourra l’être par d’autres sous-modules. Notons ici la référence à preval qui donne la valeur du signal obtenu

60

lors de la réaction précédente. La ligne 15, emit tempsNucera(tempsNucera.preval + 1), est une façon d’incrémenter un compteur.

De la ligne 19 à 23 nous avons affaire au déroulement séquentiel de cinq sous modules, déclarés selon le même procédé que celui que nous regardons. Les trois points sont une façon commode de signifier que nous passons en paramètre du module appelé tous les signaux de notre module. Quand nous arrivons en fin de notre premier fork, nous passons à la ligne 26 où tout s’enchaine dans la même réaction pour reprendre au début de loop{} en ligne 5. Notons que la ligne 34 est une instruction d’export purement JavaScript qui permet à des modules JavaScript autres que celui qui comprend ce programme, d’accéder à notre module HipHop.js. Cet exemple de module n’est pas exhaustif en termes d’instructions HipHop.js, mais il est déjà représentatif de la logique de fonctionnement de ce langage.