Chapter 18: traits that build on a trait, built
Chapter 18's Animals mixes behaviour into animals with traits: Named says every trait-bearing thing has a name; Swimmer, Flyer and Walker each build on Named and add one ability; Penguin, Duck and Crocodile take the ones that suit them. The IDE builds each construct and wires the traits; you type the values no tool can write. To play it in the IDE: Help > Lessons > Getting Started with EK9…, or ek9 -ide -lesson book-animals.
What you'll build
The lesson builds this program from a file holding only its module line - the finished file, as the book prints it.
#!ek9 defines module book.animals defines trait Named name() as pure abstract <- rtn as String? Swimmer with trait of Named swim() as pure <- rtn as String: "paddles through the water" Flyer with trait of Named fly() as pure <- rtn as String: "takes to the air" Walker with trait of Named walk() as pure <- rtn as String: "walks on land" defines class Animal as abstract name() as pure abstract <- rtn as String? category() as pure abstract <- rtn as String? default operator ? Bird extends Animal as abstract override category() as pure <- rtn as String: "bird" default operator ? Reptile extends Animal as abstract override category() as pure <- rtn as String: "reptile" default operator ? Penguin extends Bird with trait of Swimmer, Walker override name() as pure <- rtn as String: "penguin" override swim() as pure <- rtn as String: "flies through the water on stubby wings" default operator ? Duck extends Bird with trait of Swimmer, Flyer, Walker override name() as pure <- rtn as String: "duck" default operator ? Crocodile extends Reptile with trait of Swimmer, Walker override name() as pure <- rtn as String: "crocodile" override swim() as pure <- rtn as String: "glides silently through the water" default operator ? defines program Show() stdout <- Stdout() penguin <- Penguin() penguinIs <- `The ${penguin.name()} (a ${penguin.category()})` stdout.println(`${penguinIs} ${penguin.swim()} and ${penguin.walk()}.`) duck <- Duck() duckIs <- `The ${duck.name()} (a ${duck.category()})` stdout.println(`${duckIs} ${duck.swim()}, ${duck.fly()} and ${duck.walk()}.`) swimmers <- List() of Swimmer swimmers += Penguin() swimmers += Crocodile() for s in swimmers stdout.println(`the ${s.name()} ${s.swim()}`)
Step 1: A trait with an abstract method
Choose Code > New Construct > Trait…
Named is the trait's name. Type it and choose Preview.
The preview shows Named about to be written. Choose Apply.
Right-click the Named line and choose Add Method…
name is the method's name, String the return type, pure ticked, abstract ticked. Fill them in and choose Apply.
Step 2: Traits that adopt a trait
Choose Code > New Construct > Trait…
Swimmer is the trait's name. Type it and choose Preview.
The preview shows Swimmer about to be written. Choose Apply.
Right-click the Swimmer line and choose Adopt Trait…
Type Named as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Choose Code > New Construct > Trait…
Flyer is the trait's name. Type it and choose Preview.
The preview shows Flyer about to be written. Choose Apply.
Right-click the Flyer line and choose Adopt Trait…
Type Named as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Choose Code > New Construct > Trait…
Walker is the trait's name. Type it and choose Preview.
The preview shows Walker about to be written. Choose Apply.
Right-click the Walker line and choose Adopt Trait…
Type Named as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Right-click the Swimmer line and choose Add Method…
swim is the method's name, String the return type, pure ticked. Fill them in and choose Apply.
Select swim's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.
Right-click the Flyer line and choose Add Method…
fly is the method's name, String the return type, pure ticked. Fill them in and choose Apply.
Select fly's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.
Right-click the Walker line and choose Add Method…
walk is the method's name, String the return type, pure ticked. Fill them in and choose Apply.
Select walk's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.
Step 3: An abstract class
Choose Code > New Construct > Class…
Animal is the class's name. Select Abstract. Choose Preview.
The preview shows Animal as abstract. Choose Apply.
Right-click the Animal line and choose Add Method…
name is the method's name, String the return type, pure ticked, abstract ticked. Fill them in and choose Apply.
Right-click the Animal line and choose Add Method…
category is the method's name, String the return type, pure ticked, abstract ticked. Fill them in and choose Apply.
Right-click the Animal line and choose Add Operator ▸ ? (isSet) ▸ default.
Step 4: Bird and Reptile
Choose Code > New Construct > Class…
Bird is the class's name. Type Animal into the Extends: field. Select Abstract. Choose Preview.
The preview shows Bird extends Animal as abstract. Choose Apply.
Right-click the Bird line and choose Add Method…
category is the method's name, String the return type, pure ticked, override ticked. Fill them in and choose Apply.
Select category's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.
Right-click the Bird line and choose Add Operator ▸ ? (isSet) ▸ default.
Choose Code > New Construct > Class…
Reptile is the class's name. Type Animal into the Extends: field. Select Abstract. Choose Preview.
The preview shows Reptile extends Animal as abstract. Choose Apply.
Right-click the Reptile line and choose Add Method…
category is the method's name, String the return type, pure ticked, override ticked. Fill them in and choose Apply.
Select category's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.
Right-click the Reptile line and choose Add Operator ▸ ? (isSet) ▸ default.
Step 5: Penguin — a class with two traits
Choose Code > New Construct > Class…
Penguin is the class's name. Type Bird into the Extends: field. Leave Closed selected. Choose Preview.
The preview shows Penguin extends Bird, with the override its parent still owes already written. Choose Apply.
Right-click the Penguin line and choose Add Operator ▸ ? (isSet) ▸ default.
Right-click the Penguin line and choose Adopt Trait…
Type Swimmer as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Right-click the Penguin line and choose Adopt Trait…
Type Walker as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Select name's stub, from <- rtn as String: String() down to its //AI line, and type penguin's own name. Saves when typed.
Right-click the Penguin line and choose Add Method…
swim is the method's name, String the return type, pure ticked, override ticked. Fill them in and choose Apply.
Select swim's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.
Step 6: Duck — three traits
Choose Code > New Construct > Class…
Duck is the class's name. Type Bird into the Extends: field. Leave Closed selected. Choose Preview.
The preview shows Duck extends Bird, with the override its parent still owes already written. Choose Apply.
Right-click the Duck line and choose Add Operator ▸ ? (isSet) ▸ default.
Right-click the Duck line and choose Adopt Trait…
Type Swimmer as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Right-click the Duck line and choose Adopt Trait…
Type Flyer as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Right-click the Duck line and choose Adopt Trait…
Type Walker as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Select name's stub and type the duck's name. Saves when typed.
Step 7: Crocodile
Choose Code > New Construct > Class…
Crocodile is the class's name. Type Reptile into the Extends: field. Leave Closed selected. Choose Preview.
The preview shows Crocodile extends Reptile, with the override its parent still owes already written. Choose Apply.
Right-click the Crocodile line and choose Add Operator ▸ ? (isSet) ▸ default.
Right-click the Crocodile line and choose Adopt Trait…
Type Swimmer as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Right-click the Crocodile line and choose Adopt Trait…
Type Walker as the trait - Implement method stubs is already chosen - and choose OK.
Adopt Trait changes the open file in the editor, not yet saved. Choose File > Save.
Select name's stub and type the crocodile's name. Saves when typed.
Right-click the Crocodile line and choose Add Method…
swim is the method's name, String the return type, pure ticked, override ticked. Fill them in and choose Apply.
Select swim's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.
Step 8: The program
Choose Code > New Construct > Program…
Show is the program's name. Type Show and choose Preview.
The preview shows Show about to be written. Choose Apply.
Select the stub, from ready <- true down to its //AI line, and type Show's body: a penguin and a duck described, then a List of Swimmer holding a Penguin and a Crocodile. Saves when typed.
Step 9: Run it
Choose Run > Run Program…
The project's only program is already chosen. Choose Run.
The penguin (a bird) flies through the water on stubby wings and walks on land - the duck swims, flies and walks - then the penguin and the crocodile each swim their own way from one List of Swimmer. Choose Close.
The result
Animals.ek9 now reads exactly as chapter 18 of Getting Started with EK9 shows it: behaviour mixed into animals from three traits that each build on Named, with Animal's own branch of the family alongside. Adopt Trait… on a trait's name line wrote 'with trait of Named' and no stubs - a trait extends a contract, it does not implement it. AI assistants use ek9_new_construct, ek9_add_method, ek9_adopt_trait, ek9_add_operator and ek9_add_program.
Where this lesson comes from
- For AI assistants - the MCP tool
ek9_new_construct,ek9_add_method,ek9_adopt_trait,ek9_add_operator,ek9_add_program.
In the EK9 reference: Traits in EK9







































































































