points de vue - Mot-clé - slotles déambulations d'un codeur2023-06-18T04:35:57+02:00Miguel Moquillonurn:md5:2d53372d0fa8f28ff50e71462648e0b8DotclearUne histoire de slotsurn:md5:37df2868ec64fd2cb96663fca117d7a82014-03-04T11:41:00+01:002014-03-22T23:24:57+01:00Miguel MoquillonTechniques de programmationMéta-programmationprogrammation impérativeprogrammation orientée objetslot<p><img src="https://www.moquillon.fr/public/slot.png" alt="card slot" style="float:left; margin: 0 1em 1em 0;" title="card slot, mar. 2014" />L’amélioration de la structuration du code d’un programme, avec la distinction des considérations techniques de celles métier, est le Saint Graal que poursuivent sans fins les développeurs. A cette fin, de nombreuses techniques ont fait leur apparition dont nous pouvons citer les <em>traits</em> ou les <em>annotations</em>. A côté de ceux-ci, il existe une technique élégante et uniforme que sont les <em>slots</em><a href="https://www.ruby-lang.org/fr/" hreflang="fr" title="Site Web du langage Ruby"></a>. Mais, que sont ces derniers et en quoi peuvent ils nous aider dans notre quête ?</p> <p>Un adage veut qu’un bon développeur soit un développeur paresseux. Ce qui se cache derrière cette paresse est l’aptitude du codeur à automatiser ses tâches redondantes et souvent ennuyeuses et de tout faire pour faciliter son boulot. L’avantage de cette attitude est évidemment pour l’organisation un gain de productivité à terme. En fait, à y regarder de près, le développeur ne fait que s’aligner aux lois de la physique : minimiser l’entropie.
Un des aspects de cette caractéristique est, pour le programmeur, de minimiser la duplication de codes et, pour ce faire, il va user de techniques et de moyens qu’il connaît mais aussi qu’il a à sa disposition via l’outillage et surtout son langage de programmation.
La structuration du code est l’une de ces techniques. Elle est vieille de plus de 30 ans mais n’a cessé et ne cesse de continuer à évoluer. L<em>‘AOP</em> (Aspect-Oriented Programming), les <em>traits</em>, les <em>mixins</em>, les <em>closures</em>, etc. ne sont que des aspects de celle-ci dans leur objectif de modulariser non seulement le code métier mais aussi et surtout le code transversal au métier et aux fonctionnalités du logiciel. Avec l<em>‘AOP</em>, nous pouvons définir des composants d’ordre technique comme la génération de traces ou la validation des autorisations d’appel d’opérations. Ces composants sont ensuite tissés aux objets métiers à l’exécution ou à la compilation ; l<em>‘AOP</em> permet de maintenir d’un côté les caractéristiques techniques et de l’autre les modules métiers sans les entacher de considération techniques. Les <em>mixins</em> et les <em>traits</em> sont deux concepts différents permettant de définir des propriétés, d’ordre technique ou fonctionnelle, transversales aux objets métiers puis de les associer à ces derniers de manière statique ou dynamique. Par exemple, l’ordonnancement ou encore la persistance peut être définie dans un <em>mixin</em> ou un <em>trait</em>, indépendamment des objets métiers des applications. Ces deux techniques ont été popularisés respectivement par les langages <a href="https://www.ruby-lang.org/fr/" hreflang="fr" title="Le site Web du langage Ruby">Ruby</a> et <a href="http://selflanguage.org/" hreflang="en" title="Le site Web du langage Self">Self</a>. Les annotations, popularisés par <a href="http://www.java.com/fr/" hreflang="fr" title="Site Web du langage Java">Java</a>, constituent une autre technique qui permet de qualifier sémantiquement des objets et d’attacher à celles-ci un comportement qui peut aller jusqu’à la génération de codes ; par exemple, des objets peuvent être annotés avec des marqueurs de gestion des transactions ou encore d’annotations métiers propres au domaine de l’application.</p>
<p>Pourtant, il existe un autre concept popularisé par Self en même temps que les <em>traits</em> : les <em>slots</em>. Ces derniers ne sont pas nouveaux puisqu’ils furent introduit par CLOS (Common Lisp Object System). (Dans CLOS comme dans Self, ils sont appelés <em>descripteurs de slot</em>). On retrouve ces derniers dans le langage <a href="http://iolanguage.org/" hreflang="en" title="Site Web du langage IO">Io</a> et actuellement un travail est réalisé pour les intégrer à terme dans <a href="http://www.pharo-project.org/home" hreflang="en" title="Le site Web du langage Pharo">Pharo</a>. Mais qu’est-ce qu’un <em>slot</em> ou <em>descripteur de slot</em> ? Dans le contexte d’un langage orienté-objet, un <em>slot</em> est la réification du point d’accès aux propriétés d’un objet ou, plus exactement, du mécanisme d’envoi/réception de messages (cf. mon <a href="https://www.moquillon.fr/index.php/post/2012/12/21/Les-Programmations-Orient%C3%A9es-Objet">billet</a> sur les différentes POO). Tout accès aux propriétés d’un objet se fait par l’intermédiaire des slots qui, non seulement peuvent contrôler l’accès en lecture et en écriture de ces propriétés, mais aussi contenir des informations sémantiques sur celles-ci. Ils constituent une interface homogène d’accès aux propriétés de l’objet. Dans Self et <a href="http://newspeaklanguage.org/" hreflang="en" title="Le site Web du langage Newspeak">Newspeak</a>, le slot est un objet particulier qui agit comme une méthode retournant toujours une valeur (que celle-ci soit calculée dans le cas d’une méthode ou mémorisée dans le cas d’un attribut). Selon les langages de programmation, les slots peuvent n’être définis que pour l’accès aux champs d’un objet. Parce que c’est aussi un objet, le slot peut être manipulé comme n’importe quel autre objet du langage et, par voie de conséquence, il est possible alors de lui affecter aussi un comportement. Pour illustrer ceci, voici un petit exemple dans un pseudo-langage dans lequel le caractère point représente un slot (l’accès à un slot se fait par le point) :</p>
<pre>
Point.x := 3
Point.move := (abs, ord) { myself x += abs; myself y += ord; myself }
Point.move.afterInvocation := () { View current updateView(myself) }
</pre>
<p>A la première ligne, le slot réfère un champs <code>x</code> tandis qu’à la seconde ligne le slot réfère une opération <code>move</code>. Le premier retournera la valeur 3 tandis que le second, une fois son action accomplie, retournera par défaut le point lui même. La dernière ligne spécifie quoi faire à la suite de l’invocation de l’opération : mettre à jour l’IHM dans laquelle est dessiné le point. L’attribut <code>myself</code> des slots désigne l’instance de l’objet qui contient le slot. Dans la représentation ci-dessus, par homogénéité, les propriétés d’un slot (par exemple <code>afterInvocation</code>) sont elles aussi des slots (dans ce cas, il existe un slot terminal qui référence ou stocke directement la valeur de l’attribut ou les instructions de la méthode). Nous aurions pu écrire le code comme suit pour plus de lisibilité :</p>
<pre>
Point setSlot($x, 3)
Point setSlot($move, (abs, ord) { myself x += abs; myself y += ord; myself } )
Point.move setSlot($afterInvocation, () { View current updateView(myself) } )
</pre>
<p>dans lequel le signe $ désigne un symbole.</p>
<p>Parce qu’un slot peut représenter un point d’accès vers un autre objet, les relations inter-objets deviennent mécaniquement des citoyens de première classe au même titre que l’objet (ou la classe dans un langage orienté-classes). Pour illustrer ceci, imaginons un employeur qui a plusieurs employés et des employés qui est rattaché à un et un seul employeur :</p>
<pre>
Employer.employees := []
Employer.employees.onWrite := (e) { (e employer = myself) ifFalse(
{ e employer(myself) })
}
Employee.employer := None(Employer)
Employee.employer.onWrite : = (e) { (e employees contains(myself)) ifFalse(
{ e employees add(myself) })
}
</pre>
<p>Dans le code ci-dessus, chaque nouveau employé de l’employeur mettra automatiquement la référence <code>employer</code> de l’employé avec son nouveau employeur. De même, chaque mise-à-jour de l’employeur de l’employé ajoutera ce dernier parmi les employés de son nouveau employeur :</p>
<pre>
anEmployee := Employee()
anEmployer := Employer()
anEmployer employees add(anEmployee)
Assertion assertThat(anEmployee employer, is(anEmployer))
</pre>
<p>Les slots <code>employees</code> et <code>employer</code> représentent donc des relations qui peuvent être manipulés comme de simples objets et qui permettent de maintenir la cohérence des relations entre l’employeur et les employés. Nous pouvons alors introduire un mécanisme de création et de relations hiérarchiques de slots comme avec les objets (ou les classes d’objets) :</p>
<pre>
ManyToOneSlot := Slot {
oppositeSlot: Slot,
oppositeClass: Class,
initialize: (anInstance, theOppositeSlot, theOppositeClass) {
myself := anInstance
oppositeClass := System class(theOppositeClass)
oppositeSlot := oppositeClass slot(theOppositeSlot)
},
onWrite: (anInstance) {
((oppositeSlot read: anInstance) = myself ) ifFalse(
{ oppositeSlot write(myself, anInstance) } )
}
}
OneToManySlot := Slot {
oppositeSlot: Slot,
oppositeClass: Class,
initialize: (anInstance, theOppositeSlot, theOppositeClass) {
myself := anInstance
oppositeClass := System class(theOppositeClass)
oppositeSlot := oppositeClass slot(theOppositeSlot)
},
onWrite: (anInstance) {
((oppositeSlot read(anInstance)) contains(myself) ) ifFalse(
{ oppositeSlot write(myself, anInstance) } )
}
}
Employer := Object {
employees: ManyToOneSlot(self, $employer, $Employee)
}
Employee := Object {
employer: OneToManySlot(self, $employees, $Employer)
}
</pre>
<p>De la même façon, il est alors possible de définir des slots dédiés à la persistance ou encore de combiner les slots entre eux pour réaliser des traitements transverses. Ceci et le fait d’ajouter du comportement aux slots ouvrent la porte à la méta-programmation, à la réflexion, sans commune mesure avec les autres concepts. Ce que permettent l’AOP, les annotations, certains usages des mixins et des traits, peuvent toutes être réalisés par les slots et ceci d’une manière uniforme et cohérente avec les concepts de base du langage.</p>
<p>Ce petit billet vous a donné un petite présentation du concept de <em>slot</em>, illustrée avec un pseudo-langage. J’espère qu’il vous aura donné un aperçu de la puissance et de l’expressivité qui se cache derrière ce simple concept.</p>