Section 7.3

State, and self

An archetype's methods work on the instance that calls them — self is that one.

An archetype does not only carry fields: it carries methods, and each works on the instance that calls it.

archetype Character {
    name: str;
    energy: int;

    greet() {
        Console.print(text: $"I am {self.name}, energy {self.energy}.");
    }

    tire(cost: int) {
        self.energy := self.energy - cost;
    }
}

@entry(start)
object MyProgram {
    start() {
        var simon := Character(name: "Simon Magus", energy: 10);
        var helen := Character(name: "Helen", energy: 7);

        simon.tire(cost: 3);

        simon.greet();
        helen.greet();
    }
}

self names this very instance

Since 1.2.1, self was a formula you copied along. Here it takes its full meaning:

greet() {
    Console.print(text: $"I am {self.name}, energy {self.energy}.");
}

When simon.greet() runs, self is Simon; when helen.greet() runs, self is Helen. One method, written once, and every instance passes through it with its own values. In an object, self named the unique instance; in an archetype, it names the one calling.

State changes, and it stays

tire(cost: int) {
    self.energy := self.energy - cost;
}

simon.tire(cost: 3) takes 3 from Simon’s energy — and his alone: the example prints 7 for Simon and 7 for Helen, each by its own path. The change outlives the call: the instance carries its state, the methods make it live.

Fields can also be changed from outside — simon.energy := 3; is allowed. Going through a method is not a rule of the language, it is a discipline: tire says why the energy drops, where the bare assignment says nothing.

Two names do not make two instances

var alias := simon;
alias.tire(cost: 3);

After that, simon.energy dropped too — alias and simon name the same instance. Copying a variable does not copy the character: there is still one Simon, reached by two names. It is the same truth as the previous subsection’s =, seen from the other side: identity belongs to the instance, not to the name.

Your turn

  • Tire Helen by 2 and check that Simon did not move.
  • Add a rest(gain: int) method that gives energy back, and let Simon rest.
  • Write var alias := simon; alias.tire(cost: 5); then make simon greet: his energy dropped. Two names, one character.
  • Make a character greet whose energy fell to zero — nothing forbids it yet. The next subsection gives the constructor the power to impose rules at birth; section 8 will give methods the power to refuse.