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.

The EK9 IDE as the lesson opens

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…

The EK9 IDE once this is done: Choose Code > New Construct > Trait…

Named is the trait's name. Type it and choose Preview.

The EK9 IDE just before choosing Preview: Named is the trait's name

The preview shows Named about to be written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Named about to be written

Right-click the Named line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: name is the method's name, String the return type, pure ticked, abstract ticked

Step 2: Traits that adopt a trait

Choose Code > New Construct > Trait…

The EK9 IDE once this is done: Choose Code > New Construct > Trait…

Swimmer is the trait's name. Type it and choose Preview.

The EK9 IDE just before choosing Preview: Swimmer is the trait's name

The preview shows Swimmer about to be written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Swimmer about to be written

Right-click the Swimmer line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Swimmer line and choose Adopt Trait…

Type Named as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Choose Code > New Construct > Trait…

The EK9 IDE once this is done: Choose Code > New Construct > Trait…

Flyer is the trait's name. Type it and choose Preview.

The EK9 IDE just before choosing Preview: Flyer is the trait's name

The preview shows Flyer about to be written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Flyer about to be written

Right-click the Flyer line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Flyer line and choose Adopt Trait…

Type Named as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Choose Code > New Construct > Trait…

The EK9 IDE once this is done: Choose Code > New Construct > Trait…

Walker is the trait's name. Type it and choose Preview.

The EK9 IDE just before choosing Preview: Walker is the trait's name

The preview shows Walker about to be written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Walker about to be written

Right-click the Walker line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Walker line and choose Adopt Trait…

Type Named as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Right-click the Swimmer line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: swim is the method's name, String the return type, pure ticked

Select swim's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.

The EK9 IDE once this is done: Select swim's stub, from <- rtn as String

Right-click the Flyer line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: fly is the method's name, String the return type, pure ticked

Select fly's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.

The EK9 IDE once this is done: Select fly's stub, from <- rtn as String

Right-click the Walker line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: walk is the method's name, String the return type, pure ticked

Select walk's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.

The EK9 IDE once this is done: Select walk's stub, from <- rtn as String

Step 3: An abstract class

Choose Code > New Construct > Class…

The EK9 IDE once this is done: Choose Code > New Construct > Class…

Animal is the class's name. Select Abstract. Choose Preview.

The EK9 IDE just before choosing Preview: Animal is the class's name

The preview shows Animal as abstract. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Animal as abstract

Right-click the Animal line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: name is the method's name, String the return type, pure ticked, abstract ticked

Right-click the Animal line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: category is the method's name, String the return type, pure ticked, abstract ticked

Right-click the Animal line and choose Add Operator ▸ ? (isSet) ▸ default.

The EK9 IDE once this is done: Right-click the Animal line and choose Add Operator ▸ ? (isSet) ▸ default

Step 4: Bird and Reptile

Choose Code > New Construct > Class…

The EK9 IDE once this is done: Choose Code > New Construct > Class…

Bird is the class's name. Type Animal into the Extends: field. Select Abstract. Choose Preview.

The EK9 IDE just before choosing Preview: Bird is the class's name

The preview shows Bird extends Animal as abstract. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Bird extends Animal as abstract

Right-click the Bird line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: category is the method's name, String the return type, pure ticked, override ticked

Select category's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.

The EK9 IDE once this is done: Select category's stub, from <- rtn as String

Right-click the Bird line and choose Add Operator ▸ ? (isSet) ▸ default.

The EK9 IDE once this is done: Right-click the Bird line and choose Add Operator ▸ ? (isSet) ▸ default

Choose Code > New Construct > Class…

The EK9 IDE once this is done: Choose Code > New Construct > Class…

Reptile is the class's name. Type Animal into the Extends: field. Select Abstract. Choose Preview.

The EK9 IDE just before choosing Preview: Reptile is the class's name

The preview shows Reptile extends Animal as abstract. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Reptile extends Animal as abstract

Right-click the Reptile line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: category is the method's name, String the return type, pure ticked, override ticked

Select category's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.

The EK9 IDE once this is done: Select category's stub, from <- rtn as String

Right-click the Reptile line and choose Add Operator ▸ ? (isSet) ▸ default.

The EK9 IDE once this is done: Right-click the Reptile line and choose Add Operator ▸ ? (isSet) ▸ default

Step 5: Penguin — a class with two traits

Choose Code > New Construct > Class…

The EK9 IDE once this is done: Choose Code > New Construct > Class…

Penguin is the class's name. Type Bird into the Extends: field. Leave Closed selected. Choose Preview.

The EK9 IDE just before choosing Preview: Penguin is the class's name

The preview shows Penguin extends Bird, with the override its parent still owes already written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Penguin extends Bird, with the override its parent still owes already written

Right-click the Penguin line and choose Add Operator ▸ ? (isSet) ▸ default.

The EK9 IDE once this is done: Right-click the Penguin line and choose Add Operator ▸ ? (isSet) ▸ default

Right-click the Penguin line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Penguin line and choose Adopt Trait…

Type Swimmer as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Right-click the Penguin line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Penguin line and choose Adopt Trait…

Type Walker as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Select name's stub, from <- rtn as String: String() down to its //AI line, and type penguin's own name. Saves when typed.

The EK9 IDE once this is done: Select name's stub, from <- rtn as String

Right-click the Penguin line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: swim is the method's name, String the return type, pure ticked, override ticked

Select swim's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.

The EK9 IDE once this is done: Select swim's stub, from <- rtn as String

Step 6: Duck — three traits

Choose Code > New Construct > Class…

The EK9 IDE once this is done: Choose Code > New Construct > Class…

Duck is the class's name. Type Bird into the Extends: field. Leave Closed selected. Choose Preview.

The EK9 IDE just before choosing Preview: Duck is the class's name

The preview shows Duck extends Bird, with the override its parent still owes already written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Duck extends Bird, with the override its parent still owes already written

Right-click the Duck line and choose Add Operator ▸ ? (isSet) ▸ default.

The EK9 IDE once this is done: Right-click the Duck line and choose Add Operator ▸ ? (isSet) ▸ default

Right-click the Duck line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Duck line and choose Adopt Trait…

Type Swimmer as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Right-click the Duck line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Duck line and choose Adopt Trait…

Type Flyer as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Right-click the Duck line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Duck line and choose Adopt Trait…

Type Walker as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Select name's stub and type the duck's name. Saves when typed.

The EK9 IDE once this is done: Select name's stub and type the duck's name

Step 7: Crocodile

Choose Code > New Construct > Class…

The EK9 IDE once this is done: Choose Code > New Construct > Class…

Crocodile is the class's name. Type Reptile into the Extends: field. Leave Closed selected. Choose Preview.

The EK9 IDE just before choosing Preview: Crocodile is the class's name

The preview shows Crocodile extends Reptile, with the override its parent still owes already written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Crocodile extends Reptile, with the override its parent still owes already written

Right-click the Crocodile line and choose Add Operator ▸ ? (isSet) ▸ default.

The EK9 IDE once this is done: Right-click the Crocodile line and choose Add Operator ▸ ? (isSet) ▸ default

Right-click the Crocodile line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Crocodile line and choose Adopt Trait…

Type Swimmer as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Right-click the Crocodile line and choose Adopt Trait…

The EK9 IDE once this is done: Right-click the Crocodile line and choose Adopt Trait…

Type Walker as the trait - Implement method stubs is already chosen - and choose OK.

The EK9 IDE just before choosing OK: 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.

The EK9 IDE once this is done: Adopt Trait changes the open file in the editor, not yet saved

Select name's stub and type the crocodile's name. Saves when typed.

The EK9 IDE once this is done: Select name's stub and type the crocodile's name

Right-click the Crocodile line and choose Add Method…

The EK9 IDE once this is done: 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.

The EK9 IDE just before choosing Apply: swim is the method's name, String the return type, pure ticked, override ticked

Select swim's stub, from <- rtn as String: String() down to its //AI line, and type its value. Saves when typed.

The EK9 IDE once this is done: Select swim's stub, from <- rtn as String

Step 8: The program

Choose Code > New Construct > Program…

The EK9 IDE once this is done: Choose Code > New Construct > Program…

Show is the program's name. Type Show and choose Preview.

The EK9 IDE just before choosing Preview: Show is the program's name

The preview shows Show about to be written. Choose Apply.

The EK9 IDE just before choosing Apply: The preview shows Show about to be written

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.

The EK9 IDE once this is done: Select the stub, from ready <- true down to its //AI line, and type Show's body

Step 9: Run it

Choose Run > Run Program…

The EK9 IDE once this is done: 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 EK9 IDE just before choosing Close: 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

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.

The EK9 IDE when the lesson has finished

Where this lesson comes from