---
# System prepended metadata

title: Mémo méta programmation

---

# Mémo méta programmation


> Note de révision pour l'ue HMIN305.  

 
### Test with Pharo
Pour réaliser des test sur pharo on crée une nouvelle méthode pour chaque test dans une classe explicitement dédiée au test par exemple TestPile pour les test des méthode d'instance de pile. 
#### Creating test class process

1 Créer une  classe de Test qui est une sous classe de TestCase.
2 Créer une méthode setup qui initialize une instance de la classe à tester par exemple une pile p pour notre exemple. 
3 Implémenter chaque méthode de test relative à une méthode la classe à tester. Par exemple :

```pharo
 setUp
	"une pile vide"
	vide := Pile new initialize: 3.
	
	"une pile dans un état quelconque, ni vide ni pleine"
	standard := Pile new initialize: 4.
	standard push: 1.
	
	"une pile pleine"
	pleine := Pile new initialize: 2.
	pleine push: 1.
	pleine push: 2. 
```
```pharo
testPop
	self should: [ vide pop ] raise: Error.
	self testPop: standard.
	self testPop: pleine.
    
    
testPop: unePile
	"attention à ce que standard reste standard, ni vide ni pleine, pour les autres méthodes de test"
	| p1 p2 |
	p1 := unePile top.
	p2 := unePile pop.
	self deny: unePile isFull.
	self assert: p2 equals: p1.
	unePile push: p1.
	self assert: unePile top equals: p2. 
    
```
## Reflexive
Tranformation de modèle: Le fait d'avoir la possiblité de transformer un model en le modifiant. Par exemple le fait **d'ajouter une une nouvelle méthode sur une classe du langage via un programme utilisant ce mm langage** ( grace à la **relexivité** du langage et que les **classes, compilateur et les méthodes sont toute représenté par des méta objects**) .
Le résultat est directement exécutable car Pharo est un langage reflexive. 
### Example
```pharo 
testCompile
"BaseExos testCompile"
| multMethod res |
multMethod := OpalCompiler new
source: 'mult: y\ ^self = 0 ifTrue: [0] ifFalse: [^y + ((self - 1)
mult: y)]' withCRs;
class: Integer;
compile.
Integer addSelector: #mult: withMethod: multMethod.
res := multMethod valueWithReceiver: 2 arguments: #(3).
ˆ(3 mult: 4) + res
```
>Ajout de la méthode mult à la classe Integer de pharo.
 
|Type| Description|
|----|------------|
 |source| Chaine de carractère qui contient le code la méthode à ajouter|
 |multMethod := OpalCompiler new | Création d'une instance d'OpalCompiler pour pouvoir l'utiliser.|
 |class: Integer;| class: Méthode de la classe OpalCompiler, on indique qu'on peut faire une opeération sur la classe Integer|
 |Integer addSelector: | Ajout de la méthode sur la class sous le nom mult:|
### Versus static method of java or C++.
#### Method.
L'orsqu'on créer une classe une méta classe est directement crée ( par pharo). Par exemple lorsqu'on crée une classe Pile, la méta class Pile class est crée. 

Dans une méthode d'instance d'une méta class on peut utiliser  self (this) car se sont de vraie méthode qui sont definie sur des vrai class qui sont les  méta classe. 

#### Type d'attributs.
Il y'a 3 grands type d'attributs:






```pharo
Object subclass: #Pile
	slots: { #contenu. #index. #capacite }
	classVariables: { #tailleDefaut }
	package: 'HMIN305'
```

|Type| Description|
|----|------------|
|slots: { #contenu. #index. #capacite }|Attribut de classe d'instance dont les instance de classe normal ont une valeur |
|classVariables: { #tailleDefaut }|Attributs partagé par toute les instance de la classe|
|Attribut d’instance de méta-classe| Attribut défini sur une méta-classe dont la valeur est propre à chaque classe qui en est instance. Exemple : l’attribut name défini sur Class et ayant valeur pour chaque classe instance de Class.|
 Les attributs partagés sont accessible par les méthdes d'instance de la classe et dans les méthode d'instance de la méta classe. Si on fait le lien avec java, cela correspondrai à un attribut static qui est accessible par les méthode static et par les méthodes "normal". Attenton à ne pas confondre avec les attributs d'instance de la méta class.
 **Utiliser une classe comme un objcet, c'est de la méta programmation.**
 
 **Sur Pharo on peut pas créer de nouvelle méta class c'est l'une des limites de Pharo => Utilisation de comon LISP**
```pharo
p := Pile new.
p push: 3.

Pile new .
```
Pourquoi on peut envoyer le message push à p ? 
> P est une instande de la classe Pile et la classe Pile défin la mt push. 
> **Quand on envoie un msg à un objet on cherche la méthode sur sa classe.**

>Si on peut faire l'envoie de message new à Pile c'est prk la met new se trouve sur la classe de pile qui est Pile Class qui herite de bihavior. 


##### Implémentation d'un do: sur une classe List
```pharo
do: aBlock
    aBlock value: self first.
    suite ifNil: [ ^nil. ].
    suite do: aBlock.
```



##### Implémentation d'un printOn: utilisant la méthode d'instance do: sur une classe List
```pharo
printOn: aStream
    aStream nextPutAll: 'une liste, de taille '.
    self length printOn: aStream.
    self length = 1
        ifTrue: [ aStream nextPutAll: ' contenant l''element : ('. ]
        ifFalse: [ aStream nextPutAll: ' contenant les elements : ('. ].
    self do:[:each|each printOn: aStream.aStream space].
    aStream nextPut: $).
    aStream nextPut: $..
```



### Refactoring 
 Programmer une transformation de modèle

```pharo
do 

"RefactorPile do"

	| growCompiledMethod pushMethod newClass classPile |
	
	saveGrow
		ifNil: [ self
				error:
					'action impossible à cet instant,
			      définir grow sur Pile puis éxécuter "RefactorPile initialize" avant de relancer' ]
		ifNotNil: [ 
			"c'est parti"
			"défaire l'exercice s'il a déjà été fait, pour pouvoir le refaire"
			"self undo."

			"rérérencer la classe Pile dans une variable"
			classPile := Smalltalk classNamed: #Pile.
			
			"créer la classe #PileGrossissante, si elle n'existe pas déjà"
			"créée dans le même package que Pile"
		classPile
				subclass: #PileGrossissante
				instanceVariableNames: ''
				classVariableNames: ''
				package: classPile category.	

			"rérérencer la classe PileGrossissante dans une variable"
			newClass := Smalltalk classNamed: #PileGrossissante.

			"récupérer la méthode compilée grow dans le dictionnaire des méthodes de Pile"
			growCompiledMethod := Pile compiledMethodAt: #grow.
			
			"enlever la clé grow du dictionnaire des méthodes de la classe Pile"
			Pile removeSelector: #grow.

			"ajouter la méthode récupérée au dictionnaire des méthodes de PileGrossissante"
			newClass addSelector: #grow withMethod: growCompiledMethod.

			"fabriquer le code de la méthode push: de PileGrossissante, et le compiler"
			"; est la cascade de message"
			pushMethod := OpalCompiler new
				source:
					'push: o\  self isFull\    ifTrue: [self grow].\  ^super push: o'
						withCRs;
				class: newClass;
				compile.

			"ajouter la nouvelle méthode compilee dans le dictionnaire des méthodes de la nouvelle classe"
			newClass addSelector: #push: withMethod: pushMethod.
			
			"SystemAnnouncer uniqueInstance methodAdded: pushMethod."
		
			"en principe c'est terminé, on peut exécuter le test"]

```

### Throw catch

#### Catch

```pharo
catch: aBlock
    "execute aBlock with a throw possibility"
    aBlock value.
```
>Exécute le block reçu en argument.

```pharo
returnToCatchWith: aValue
"Look down the stack for a catch, the mark of which is self,
when found, transfer control (non local branch).”
”Version Visualworks"
| catchMethod currentContext |
currentContext := thisContext.
catchMethod := Symbol compiledMethodAt: #catch:.
[currentContext method == catchMethod and: [currentContext receiver ==
self]]
whileFalse: [currentContext := currentContext sender].
thisContext sender: currentContext sender.
ˆaValue
```
> Chercher dans la pile d exécution un catch. L'orsqu'on éxecute un block on l'empile dans la pile d execution et le block est exécuté. 


###### ThisContext : Bloc de pile courant.
>On cherche dans le bloc de pile courant si la méthode qui la créer = catch methode et si le receuveur de l envoie de msg qui créer le blog courant = self qui est le symbol auquel j'ai envoyé le msg. Tant que la condition n'est âs vérifiée on descent dans la pile je desnet dans la pile.
>Quand la condition est vérifée currentConext contient le block de pille correspondant a l'invocation de catch. On invoque ensuite la méthode return.


 #### Example
 ```pharo
 ˆ#Essai catch: [
Transcript show: 'a';cr.
Transcript show: 'b';cr.
Transcript show: 'c';cr.
#Essai returnToCatchWith: 22.
Transcript show: 'd';cr.
33]
```
### Les mémo class en pĥaro 
 Pour réaliser une **mémo-class** en pharo il faut:
 - Ajouter un attribut de class partagé **listInstance**
 - Redéfinir la méthode **new**
  ```pharo
new
ˆself new: tailleDefaut.
  )
 ```
  - Redéfinir la méthode **new:**
   ```pharo
new: taille
| newInst |
newInst := super new initialize: taille.
listeInstance add: newInst.
ˆnewInst
 ```
## Ue autre solution  pour faire des méta class : Comon lisp ou ObjvList
### Les mémo class en Lisp

>Pour réaliser une mémo class en lisp il faut créer une sous classe qui hérite de memo-class. Memo-class étant une classe qui  représente tout object qui sauvegarde la liste de toutes ses instances. 

#### Memo class
 ```pharo
; Mémo-classe.
(defclass memo-class (standard-class)
  (
   (instance-set :accessor class-instance-set
                 :initform nil)
   )
  (:metaclass standard-class)
  )
```
#### Memo-object
 ```pharo
; Mémo-objet.
(defclass memo-object (standard-object)
  ()
  (:metaclass standard-class)
  )
```
Pour implémenter le mécanisme de sauvegarde d'instance on doit redéfinr les la méthode new. Ceci permettra d'ajouter chaque instance crée à la liste des instance.
 ```pharo
; Définition de la méthode make-instance de memo-class.

(defmethod make-instance ((mc memo-class) &rest initargs)
  (let ((instance (call-next-method)))
    ; On ajoute instance à notre ensemble d'instances.
    (setf (class-instance-set mc)
          (cons instance (class-instance-set mc))
          )
    ; On renvoit l'instance créée.
    instance)
  )
```
Enfin pour finir il faut vérifier si l'héritage est autorisé pour toute classe qui prétent etre une memo-class.
 ```pharo
; Validations d'héritage avec validate-superclass.
; ---------------------------------------------------------------------

; Si memo-class hérite de memo-class, tout va bien.
(defmethod validate-superclass ((memo memo-class) (sup memo-class))
  T
  )

; Si c'est l'inverse, rien ne va plus.
(defmethod validate-superclass ((std standard-class)(memo memo-class))
  nil
  )

; Si on hérite d'une standard-class, il faut tester qu'elle soit memo-object
(defmethod validate-superclass ((memo memo-class) (sup standard-class))
  ; Ne devrait-ce pas être un test pour 'memo-class ?
  (eq (class-name sup) `memo-object)
  )

```
#### Exemple: Nous allons faire de Point une mémo class
 > Création d'une simple class Point
 ```pharo
(defclass Point (memo-object)
((x :initform 1 ;;valeur par défaut de l’attribut
:initarg :x ;;nom de l’initialiseur
:accessor getx ;;nom de l’accesseur en lecture et écriture
)
(y :initform 2 :initarg :y :accessor gety)
(z :accessor getz :initarg :z :allocation :instance))
(:metaclass memo-class)
)

```
> Point **hérite de memo-object** ( contrat à respecter pour etre une mémo-class). Sa **méta class** est tout naturellement **memo-class**.  

##### Test
 ```pharo
 ; Récupération des instances.
(defun get-instances (mc)
  (class-instance-set (find-class mc))
  )
  
 ;; Test 
(setf p1 (make-instance 'point :x 19)) 

(setf p2 (make-instance 'point :x 20))
(print "Instance P1 " )
(print P1)

(print "Instance P2 " )
(print P2)

(print "Liste des instance :  " )
(print (get-instances 'point))

```
Sortie sur le terminal:
 ```bash

"Instance P1 " 
#<POINT #x0000008000364E69> 
"Instance P2 " 
#<POINT #x0000008000365A21> 
"Liste des instance :  " 
(#<POINT #x0000008000365A21> #<POINT #x0000008000364E69>) 
```

## Partie EMF
Schéma EMF

![](https://i.imgur.com/tWrOh6p.png)

 

### Comment faire une méta class en utilisant EMF
L'idee est d aller modifier les concept des diff langage utilisés, ici ecore dans la couche M3 :
 - Reprendre le niveau méta méta donc  M3
 - Mettre ce niveau dans eclipse pour que le noyau devient modifiafble  via un téléchargement  du noyau M3 vers le niveau M2.
 - Une fois les modif terminé  grace au outils et editors on  le remonte dans le niveau M3 pour pouvoir utiliser les concepts qui ont été définie.
 
 

## smalltalk Vs CLOS
Avantages :
 - pas de typage statique, tout est gérer en typage dynamique
 - exécution d'une portion de code sans avoir à ce soucier de la déclaration d'une fonction main (internet)
 - le système de métaclass implicite de smalltalk permet de gérer les incompatibilité ascendant et descendant

Inconvénient :
  - possède des incompatibilité sémantique (qu'il faudra expliqué)
  - à cause de l'isomorphisme, impossible de créer des nouvelles métaclass (donner des exemples)
# savoir faire:

- Gestions des classe  et méta class de manière **implicite** (Pharo)
    - memo class
    - faire d'une classe une mémo classe
    - expliquer les différents types d attributs
    - introspection en pharo
    - justifier les envoie de msg new selon le context
    -  Refactoring de class 
    -  Expliquer la mise en place du try catch
    -  Créer une classe test pour une classe donnée 
    -  créer une classe, sous classe , classe abstraite
    -  Introspection MyInspector
- Gestions des classe  et méta class de manière **explicite** ( Lisp / objvList)
    - memo class
    - faire d'une classe une mémo classe
    - expliquer les différents types d attributs
    - introspection 
    - justifier les envoie de msg new selon le context
    - 
 

- question sur EMF

 ## FAQ
 - Définition
     - Langage explicite : Contrairement au système implicite ou les méta classes sont créées de manière implicite lorqu'on crée une classe. Les système explicite comme Clos offre au développeur  la possibilité de choisir la classe de la classe crée. Attention cependant à cette liberté qui peut engendrer des problème de compatibilité méta-class / super class. Une des solution que nous pouvons adopter face à ce problème est la mise en place de méthode  ( ex: validate-superlass ) de controle de compatibilité. Comment nous l'avons vus lors de l'étude de la mise en place d'une mémo-class en utlisant CLOS. 
     - ObjvLisp est un système à metaclasse explicite inspiré du noyaux smalltalk 78 et sous ensemble du noyaux réfléxif de CLOS. Le modèle minimal comporte uniquement une classe "Class" et une class "Object". Object est instance de Class et Class est instance de lui même pour éviter la régression infinie. Class hérite aussi de Object pour implémenter la réification des classes et la métaprogrammation + schéma
     - Introspection : connexion causale unidirectionnelle, RU reflète RE, si RE change RU change mais la réciproque est fausse.
     - Réflexivité : Capacité qu’a un système à donner à ses utilisateurs une représentation, un modèle, de lui-même en relation (ou connexion) causale avec sa représentation effective (en machine dans le cas d’un système informatique).
