Tuples can extend other tuples. TUPLE: child < parent slots ;
declares a class whose instances are also instances of parent
— they get the parent's slots in addition to their own, and the
parent's accessors work on them too, just as if they'd been defined on
the child.
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 slot orderThe boa constructor takes slots in declaration order, parents
first. For dog above:
dog boa ( name age breed -- dog )
A grandchild puppy < dog adding weeks would be:
puppy boa ( name age breed weeks -- puppy )
Every TUPLE: declaration generates a predicate (name?).
With inheritance the predicates nest — every descendant
satisfies its ancestors' predicates:
"Rex" 4 "labrador" dog boa
dup dog? . ! => t
dup animal? . ! => t
The reverse isn't true: an animal that isn't a dog fails
dog?.
Generic methods (M:, taught in generics)
dispatch up the hierarchy too — a method on animal fires for
every descendant unless a more-specific override takes
priority. You'll see that in boatswains-bilge immediately
after this exercise.
A naturalist is cataloguing the dragons that live around the caldera. They share traits with one another — every dragon has a name, colour, and age — but specialise in distinctive ways. You'll build a small inheritance tree of dragon classes and a single word that ages any descendant.
Define the whole inheritance tree of tuple classes up front (their constructors come in the tasks that follow):
dragon with slots name, color, age.fire-dragon, a subclass of dragon, adding a flame-temp slot.ice-dragon, another subclass of dragon, adding a chill-temp
slot.volcano-dragon, a subclass of fire-dragon, adding a
lava-volume slot.Then give dragon a <dragon> constructor.
"Falkor" "white" 100 <dragon> name>> . ! => "Falkor"
Give fire-dragon a <fire-dragon> constructor.
"Smaug" "red" 500 1200 <fire-dragon> flame-temp>> . ! => 1200
"Smaug" "red" 500 1200 <fire-dragon> dragon? . ! => t
Give ice-dragon a <ice-dragon> constructor.
"Frosty" "blue" 200 -40 <ice-dragon> chill-temp>> . ! => -40
"Frosty" "blue" 200 -40 <ice-dragon> fire-dragon? . ! => f (siblings)
Give volcano-dragon a <volcano-dragon> constructor.
"Vesuvius" "red" 1000 1500 99 <volcano-dragon> dragon? . ! => t
"Vesuvius" "red" 1000 1500 99 <volcano-dragon> fire-dragon? . ! => t
Define age-dragon to increment the age slot of any dragon
(or descendant) by one. Returns nothing.
"Falkor" "white" 100 <dragon> dup age-dragon age>> . ! => 101
The same word should work on every descendant — that's the whole point of the shared accessor.
Sign up to Exercism to learn and master Factor with 47 concepts163 exercises, and real human mentoring, all for free.