In the last lesson, structs were always copied, like photocopies. That's great for small values like points and money. But some things in a program aren't meant to be copied: there's only one player in a game, one bank account, one scoreboard, and every part of the program should see the same one. For those, steav2 has classes.
What is a tnak?
tnak means class. Like a sampoan, a class is a type you design, with fields and methods. The big difference is how you build one, and what happens when you share it.
bongSlanhOun "counter";
tnak Counter {
akthe count: LekKut;
rupamun init() {
nis.count = 0;
}
rupamun tick() {
nis.count += 1;
}
}
akthe clicks = Counter();
clicks.tick();
clicks.tick();
clicks.tick();
jongyeytha clicks.count; 3 Two new things here:
rupamun initis a special method that runs automatically when you build a new object withCounter(). It initializes (sets up) the fields. A class must set its fields itself ininit, instead of listing them in brackets like a struct.nismeans this: "the object this method belongs to".nis.countmeans "this counter's count". (You can also just writecount, like in struct methods, butnis.makes it very clear.)
The value you build from a class is called an object or an instance.
Unlike a struct's method, a class's method can change its fields: tick() really does add one to the count.
Giving init some inputs
init can take parameters, just like any function. Whatever you put in the brackets when building the object gets passed to init:
bongSlanhOun "player";
tnak Player {
akthe name: Ahsor;
akthe health: LekKut;
rupamun init(name: Ahsor) {
nis.name = name;
nis.health = 100;
}
rupamun hurt(damage: LekKut) {
nis.health -= damage;
ber (nis.health <= 0) {
jongyeytha nis.name + " is knocked out!";
}
}
}
akthe hero = Player("Neary");
hero.hurt(30);
jongyeytha hero.name + " has " + hero.health + " health";
hero.hurt(80); Neary has 70 health
Neary is knocked out! Notice nis.name = name;: the parameter is called name and so is the field. nis.name is the field, and plain name is the parameter. That's a handy reason to use nis..
Shared, not copied
Here's the big difference from sampoan. When you put an object into another variable, you don't get a copy. Both variables point at the same object, like two people holding the same balloon by two strings:
bongSlanhOun "shared";
tnak Scoreboard {
akthe points: LekKut;
rupamun init() {
nis.points = 0;
}
}
akthe mine = Scoreboard();
akthe yours = mine;
yours.points += 50;
jongyeytha mine.points;
jongyeytha yours.points; 50
50 We only changed yours, but mine changed too, because there's only one scoreboard. Compare that with the Point copy in the last lesson.
The same goes for functions. Hand an object to a function, and the function works on the very same object, so its changes stick:
bongSlanhOun "bank";
tnak Account {
akthe balance: LekKut;
rupamun init(start: LekKut) {
nis.balance = start;
}
}
rupamun payPocketMoney(account: Account) {
account.balance += 5;
}
akthe savings = Account(20);
payPocketMoney(savings);
payPocketMoney(savings);
jongyeytha "Savings: " + savings.balance; Savings: 30 Printing an object directly just tells you what kind of object it is:
bongSlanhOun "print";
tnak Robot {
rupamun init() {}
}
jongyeytha Robot(); <Robot instance> Arrays are shared too
Surprise: you've been using a shared type all along! Arrays behave like classes, not structs. Two variables holding "the same" array really hold one array:
bongSlanhOun "shared arrays";
akthe list = ["eggs"];
akthe sameList = list;
sameList.push("milk");
jongyeytha list; [eggs, milk] sampoan or tnak?
sampoan (struct) |
tnak (class) |
|
|---|---|---|
| building | Point(1, 2), fields in order |
Player("Neary"), runs init |
| assigning or passing | makes a copy | shares the same one |
| methods can change fields | no | yes |
| good for | small values: points, colours, money | things with one identity: players, accounts, scenes |
A good rule of thumb: if two things with the same values are really the same thing (two Point(1, 2)s are equally good), use sampoan. If it's something with its own identity that changes over time (your bank account isn't the same as mine, even with the same balance), use tnak.
Your turn
- Make a
tnak Lampwith aBooleanfieldon, startingort, and a methodflip()that switches it. Hint:nis.on = !nis.on; - Give the
Playerclass aheal(amount: LekKut)method that never lets health go above 100. - Make two variables that share one
Lamp, flip it using one variable, and printonusing the other.
Solution for exercise 1:
bongSlanhOun "lamp";
tnak Lamp {
akthe on: Boolean;
rupamun init() {
nis.on = ort;
}
rupamun flip() {
nis.on = !nis.on;
}
}
akthe lamp = Lamp();
lamp.flip();
jongyeytha "on: " + lamp.on;
lamp.flip();
jongyeytha "on: " + lamp.on; on: ok
on: ort