next up previous contents index
Next: Fonction générique prédéfinie Up: Fonction générique Previous: Présentation   Contents   Index

Subsections

Fonctions génériques

Les fonctions génériques vont permettre de définir des méthodes applicables aux objets.

Déclaration

Les fonctions génériques se déclarent avec define-generic et se définissent avec define-method.

La première forme, define-generic, déclare la variable Scheme correspondante à la fonction générique :

; Déclaration d'une méthode
Osm> (define-generic f)
  => #unspecified

Utilisation

Une fois que la fonction générique est déclarée, elle peut être utilisée :

; Invocation de la méthode
Osm> (f)
  => OsmError: f: no generic method found for `()'

L'erreur obtenue indique qu'aucune méthode n'est définie pour la liste d'argument donnée, c'est à dire la liste vide.

Définition

Pour définir une méthode, nous utilisons define-method :

; Définition de la méthode
Osm> (define-method (f)
      (display "(f)\n"))
  => #unspecified

Nous venons de définir une méthode f lorsque f sera invoquée sans argument. Essayons :

Osm> (f)
  => (f)
  => #unspecified

L'intérêt des fonctions génériques est de permettre de réutiliser le nom de la méthode pour d'autres arguments :

; Spécialisation avec un argument
Osm> (define-method (f a)
      (display "(f a)\n"))
  => #unspecified

Cette méthode sera invoquée lorsque f sera appliquée à un argument, quel que soit son type :

Osm> (f 1)
  => (f a)
  => #unspecified

Pour deux arguments de n'importe quel type :

; Spécialisation avec deux arguments
Osm> (define-method (f a b)
      (display "(f a b)\n"))
  => #unspecified

Osm> (f 1 #\a)
  => (f a b)
  => #unspecified

Spécialisation

Mais ça ne s'arrête pas là : il est possible d'augmenter la résolution en précisant le type des arguments. Définissons la méthode f, appliquée à un entier de la classe  :

; Spécialisation avec un argument <integer>
Osm> (define-method (f (a <integer>))
      (display "(f <integer>)\n"))
  => #unspecified

Osm> (f #\a)
  => (f a)
  => #unspecified

Osm> (f 1)
  => (f <integer>)
  => #unspecified

La méthode f a été spécialisée pour un seul argument entier. La définition pour un seul argument d'un autre type reste toujours valide.

Cela est applicable pour tous les arguments :

; Spécialisation avec deux arguments,
; dont le second <integer>
Osm> (define-method (f a (b <integer>))
      (display "(f a <integer>)\n"))
  => #unspecified

Ici, on spécialise f lorsque son second argument appartient à la classe .

Lorsque OpenScheme applique une méthode générique à des arguments, il commence à compter le nombre des arguments, puis il recherche dans un arbre interne la méthode correspondant le mieux à la classe des arguments, en commençant par la classe la plus spécialisée. Une classe A est plus spécialisée qu'une classe B lorsque A hérite de B.

Tout objet Scheme appartient à la classe primitive . Lorsque l'on définit une méthode avec un argument sans type, en fait le type associé à celui-ci est . Ceci permet d'avoir un comportement orthogonal.

Les méthodes génériques ne permettent pas de définir des fonctions avec des arguments facultatifs, comme c'est le cas en Scheme.

Précédence

Le système objet ne se contente pas de sélectionner la méthode la plus adéquate en fonction des arguments passés : il permet à une méthode d'invoquer la méthode qui aurait était invoquait si elle n'avait pas été définie. Cette invocation se fait à l'aide de la fonction spéciale next-method :

; déclaration de la fonction générique
Osm> (define-generic g)
  => #unspecified

; définition dans le cas général
Osm> (define-method (g a)
      (display "cas <root>\n"))
  => #unspecified

; spécialisation 
Osm> (define-method (g (a <integer>))
      (next-method)
      (display "cas <integer>\n"))
  => #unspecified

; essais du cas <root>
Osm> (f #\a)
  => cas <root>
  => #unspecified

; essais du cas <integer>
Osm> (f 123)
  => cas <root>
  => cas <integer>
  => #unspecified

L'invocation de next-method se fait sans argument. En fait, cet appel est remplacé par l'appel à la méthode suivante dans l'arbre de recherche, avec tous les arguments.

Cela permet de chaîner les méthodes. Si aucune méthode moins spécialisée, l'invocation de next-method ne provoque pas d'erreur.


next up previous contents index
Next: Fonction générique prédéfinie Up: Fonction générique Previous: Présentation   Contents   Index
© 1993 to 2001 Erian Concept