Les tuples peuvent en étendre d'autres. TUPLE: child < parent slots ; déclare une classe dont les instances sont aussi des instances de parent : elles reçoivent les slots du parent en plus des leurs, et les accesseurs du parent s'appliquent aussi à elles, comme s'ils avaient été définis sur l'enfant.
USING: accessors ;
TUPLE: animal name age ;
TUPLE: dog < animal breed ;
"Rex" 4 "labrador" dog boa .
! => T{ dog { name "Rex" } { age 4 } { breed "labrador" } }
"Rex" 4 "labrador" dog boa name>> . ! => "Rex" (inherited accessor)
boa
Le constructeur boa prend les slots dans l'ordre de déclaration, les parents d'abord. Pour dog ci-dessus :
dog boa ( name age breed -- dog )
Pour un petit-enfant puppy < dog qui ajoute weeks, ce serait :
puppy boa ( name age breed weeks -- puppy )
Chaque déclaration TUPLE: génère un prédicat (name?). Avec l'héritage, les prédicats s'imbriquent, et tout descendant satisfait les prédicats de ses ancêtres :
"Rex" 4 "labrador" dog boa
dup dog? . ! => t
dup animal? . ! => t
L'inverse n'est pas vrai : un animal qui n'est pas un dog échoue au prédicat dog?.
Les méthodes génériques (M:, présentées dans generics) remontent elles aussi la hiérarchie : une méthode définie sur animal s'applique à tous ses descendants, à moins qu'une méthode plus spécifique ne prenne le pas. Tu le verras dans boatswains-bilge, juste après cet exercice.
Un naturaliste est en train de cataloguer les dragons qui vivent autour de la caldeira. Ils ont des traits en commun (chaque dragon a un nom, une couleur et un âge), mais chacun se spécialise à sa manière. Tu vas construire un petit arbre d'héritage de classes de dragons et un seul mot qui fait vieillir n'importe quel descendant.
Définis d'entrée de jeu tout l'arbre d'héritage des classes de tuples (leurs constructeurs arrivent dans les tâches suivantes) :
dragon avec les slots name, color et age.fire-dragon, une sous-classe de dragon, avec un slot flame-temp en plus.ice-dragon, une autre sous-classe de dragon, avec un slot chill-temp en plus.volcano-dragon, une sous-classe de fire-dragon, avec un slot lava-volume en plus.Donne ensuite à dragon un constructeur <dragon>.
"Falkor" "white" 100 <dragon> name>> . ! => "Falkor"
Donne à fire-dragon un constructeur <fire-dragon>.
"Smaug" "red" 500 1200 <fire-dragon> flame-temp>> . ! => 1200
"Smaug" "red" 500 1200 <fire-dragon> dragon? . ! => t
Donne à ice-dragon un constructeur <ice-dragon>.
"Frosty" "blue" 200 -40 <ice-dragon> chill-temp>> . ! => -40
"Frosty" "blue" 200 -40 <ice-dragon> fire-dragon? . ! => f (siblings)
Donne à volcano-dragon un constructeur <volcano-dragon>.
"Vesuvius" "red" 1000 1500 99 <volcano-dragon> dragon? . ! => t
"Vesuvius" "red" 1000 1500 99 <volcano-dragon> fire-dragon? . ! => t
Définis age-dragon pour incrémenter de un le slot age de n'importe quel dragon (ou descendant). Ne renvoie rien.
"Falkor" "white" 100 <dragon> dup age-dragon age>> . ! => 101
Le même mot doit fonctionner sur tous les descendants : c'est tout l'intérêt de l'accesseur partagé.
Inscris-toi sur Exercism pour apprendre et maîtriser Factor avec 47 concepts163 exercices, et un vrai mentorat humain, le tout gratuitement.