© 2007—2008 - Renaud Blanch
Ce document donne une présentation de l'extension objet pour le langage Tcl 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
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
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
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
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
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 100Il 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