Las tuplas pueden extender otras tuplas. TUPLE: child < parent slots ;
declara una clase cuyas instancias también son instancias de parent:
heredan los slots del padre además de los suyos propios, y los accesores
del padre también funcionan en ellas, como si se hubieran definido en la
clase hija.
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
El constructor boa recibe los slots en orden de declaración, primero
los padres. Para el dog de arriba:
dog boa ( name age breed -- dog )
Un nieto puppy < dog que añada weeks sería:
puppy boa ( name age breed weeks -- puppy )
Cada declaración TUPLE: genera un predicado (name?).
Con la herencia, los predicados se anidan; todo descendiente
cumple los predicados de sus ancestros:
"Rex" 4 "labrador" dog boa
dup dog? . ! => t
dup animal? . ! => t
Lo contrario no se cumple: un animal que no es un dog no pasa
dog?.
Los métodos genéricos (M:, que se enseñan en generics)
también se despachan hacia arriba por la jerarquía: un método definido en
animal se ejecuta para todos sus descendientes, a menos que una
sobrescritura más específica tenga prioridad. Lo verás en
boatswains-bilge justo después de este ejercicio.
Un naturalista está catalogando los dragones que viven alrededor de la caldera. Todos comparten ciertos rasgos (cada dragón tiene un nombre, un color y una edad), pero se especializan de maneras muy propias. Vas a construir un pequeño árbol de herencia de clases de dragones y una sola palabra que envejece a cualquier descendiente.
Define por adelantado todo el árbol de herencia de clases tuple (sus constructores vienen en las tareas que siguen):
dragon, con las ranuras name, color y age.fire-dragon, una subclase de dragon, que añade una ranura flame-temp.ice-dragon, otra subclase de dragon, que añade una ranura chill-temp.volcano-dragon, una subclase de fire-dragon, que añade una ranura lava-volume.Después, dale a dragon un constructor <dragon>.
"Falkor" "white" 100 <dragon> name>> . ! => "Falkor"
Dale a fire-dragon un constructor <fire-dragon>.
"Smaug" "red" 500 1200 <fire-dragon> flame-temp>> . ! => 1200
"Smaug" "red" 500 1200 <fire-dragon> dragon? . ! => t
Dale a ice-dragon un constructor <ice-dragon>.
"Frosty" "blue" 200 -40 <ice-dragon> chill-temp>> . ! => -40
"Frosty" "blue" 200 -40 <ice-dragon> fire-dragon? . ! => f (siblings)
Dale a volcano-dragon un constructor <volcano-dragon>.
"Vesuvius" "red" 1000 1500 99 <volcano-dragon> dragon? . ! => t
"Vesuvius" "red" 1000 1500 99 <volcano-dragon> fire-dragon? . ! => t
Define age-dragon para incrementar en uno la ranura age de cualquier dragón (o descendiente). No devuelve nada.
"Falkor" "white" 100 <dragon> dup age-dragon age>> . ! => 101
La misma palabra debe funcionar en todos los descendientes: ese es justamente el objetivo del accesor compartido.
Regístrate en Exercism para aprender y dominar Factor con 47 conceptos163 ejercicios y mentoría humana real, todo gratis.