~ / M2PGI / IHM / tps / doc /

HOWTO gmlObject

© 2007—2008 - Renaud Blanch

Ce document donne une présentation de l'extension objet pour le langage Tcl gmlObject.

Utiliser gmlObject

gmlObject est une extension objet pour Tcl. Elle est proposée sous deux formes : un script Tcl gml_Object.tcl ou une extension binaire à compiler gmlObject (version compilée pour SunOS et Tcl 8.4.9). Les deux formes sont équivalentes, la première est plus facile à utiliser puisqu'il n'y a pas besoin de compiler d'extension. La version binaire est plus efficace (la différence ne sera pas perceptible lors de nos TPs). Elle affiche surtout des messages d'erreur plus faciles à interpréter.

La version script peut servir de solution de repli si la version binaire n'est pas disponible. En plaçant les deux versions dans votre répertoire IHM/, un script situé dans IHM/TP0/ pourra commencer par :

set gmlObjectPath [file join [file dirname [info script]] ..]
if {[catch {load [file join $gmlObjectPath  libgmlobject.so]}]} {
   source [file join $gmlObjectPath gml_Object.tcl]
}
Il essaiera alors de charger la version binaire, puis, si ce chargement échoue, il reviendra à la version script.

En mode interactif, on pourra procéder de même.

% load libgmlobject.so

Des classes et des instances

Création des classes

gmlObject offre une commande method qui permet de créer des méthodes (fonctions membres attachées à une classe). Créer une méthode crée par la même occasion la classe à laquelle elle est associée. On peut ensuite créer des instances de cette classe et appeler leurs méthodes. À l'intérieur de ces méthodes, la variable objName permet d'accéder au nom de l'instance :

% method Rectangle area {} { return "the area of $objName" }
% Rectangle rectangle1
rectangle1
% rectangle1 area
the area of rectangle1

Création des instances

Les classes servent à encapsuler des données (attributs des instances). Ces attributs sont initialisés par une méthode particulière, le constructeur. gmlObject fournit une méthode nommée constructor qui sera appelée lors de la construction des instances. Les attributs peuvent être stockés dans un dictionnaire accessible par this à l'intérieur du corps des méthodes :

% method Rectangle constructor {width height} {
   set this(width) $width
   set this(height) $height
}
% method Rectangle area {} { return [expr $this(width) * $this(height)] }
% Rectangle rectangle2
wrong # args: should be "Rectangle rectangle2 width height"
% Rectangle rectangle2 20 50
rectangle2
% rectangle2 area
1000

this est aussi une commande qui permet, toujours à l'intérieur des méthodes, d'appeler les autres méthodes de cette même instance.

% method Rectangle string {} {
   return "$objName, width=$this(width), height=$this(height), area=[this area]" 
}
% rectangle2 string
rectangle2, width=20, height=50, area=1000

Destruction des instances

Chaque classe a une méthode spéciale dispose qui permet de détruire les instances. Elle appelle, si elle existe, la méthode spéciale destructor.

% rectangle1 dispose
% rectangle1 area
invalid command name "rectangle1"
% method Rectangle destructor {} { puts "disposing $objName" }
% rectangle2 dispose
disposing rectangle2

Héritage

Le lien d'héritage entre deux classe est spécifié par la commande inherit. Quand une méthode surcharge une autre méthode, elle peut appeler la version de la classe dont elle hérite grâce à une méthode magique inherited, utile en particulier dans les constructeurs :

% inherit Carre Rectangle
% method Carre constructor {width} {
   this inherited $width $width
}
% Carre carre 10
carre
% carre area
100

Plus loin

Visibilité

La création d'une instance crée en fait deux objets Tcl portant le même nom : une commande, et un tableau associatif, de la même manière que this a les deux rôles dans le corps des méthodes. Le tableau permet d'accéder aux attributs, et la commande d'appeler les méthodes :

% puts $carre(width); # tableau
10
% carre area; # commande
100
Il convient de distinguer les deux objets car ils n'ont pas les mêmes règles de visibilité. En Tcl, une commande est visible partout, il n'y a pas de restriction sur sa portée. Le tableau crée pour stocker les attributs de l'instance est une variable globale, ce qui veut dire qu'elle ne sera visible dans le corps d'une fonction qu'à condition de le déclarer explicitement grâce à la commande Tcl global :
method Circle constructor {radius} { 
   set this(radius) $radius 
}
method Circle area {} { 
   return [expr $this(radius) * $this(radius) * 3.14159] 
}

proc test {} {
   Circle circle 10
   # circle exists as a command (visible here) ...
   puts [circle area]
   
   # ... and as a global array (not visible)
   # won't work
#  puts $circle(radius)

   # make circle global variable visible in local scope
   global circle
   puts $circle(radius)
}

mise à jour : 10 octobre 2007