Encapsulation & Accessors
Encapsulation hides a class’s internal state behind a controlled surface. Zeus gives you access
modifiers to mark what’s internal, and accessors (get/set) to expose properties that run code
instead of touching a field directly.
Access modifiers
Every field and method carries one of three access levels:
public— reachable from anywhere.private— reachable only from within the same class.protected— reachable from within the same class and its subclasses, but not from outside the class hierarchy.
class Account { private balance: i32; public id: i32;
constructor(id: i32) { this.id = id; this.balance = 0; }
public deposit(amount: i32): void { this.balance = this.balance + amount; }
public getBalance(): i32 { return this.balance; }}
function main(): i32 { let a: Account = new Account(1); a.deposit(42); // a.balance = 0; // error: 'balance' is private return a.getBalance(); // => 42}Keeping balance private means it can only change through deposit, so the class controls its own
invariants.
Protected: sharing with subclasses
private shuts a member off from everything but its own class — including subclasses. Use
protected when a base class wants to keep a member internal to the outside world but still let its
subclasses read and override it:
class Animal { protected legs: i32; constructor(legs: i32) { this.legs = legs; }}
class Dog extends Animal { constructor() { super(4); }
describe(): i32 { return this.legs; // ok: protected members are visible to subclasses }}
function main(): i32 { let d: Dog = new Dog(); // d.legs; // error: 'legs' is not accessible from outside the hierarchy return d.describe() * 10 + 2; // => 42}If legs were private, the this.legs read inside Dog would be a compile error. See
Inheritance for how subclasses build on their base.
Getters
A getter is a method declared with get that you read like a field. It’s ideal for values
computed from internal state rather than stored directly:
class Circle { private r: i32; constructor(r: i32) { this.r = r; }
get area(): i32 { return this.r * this.r; // computed on each read }}
function main(): i32 { let c: Circle = new Circle(5); return c.area; // read like a field, no parentheses => 25}Setters
Pair a getter with a set accessor to make an assignable property. The setter receives the assigned
value as its parameter:
class Temp { private c: i32; constructor(c: i32) { this.c = c; }
get celsius(): i32 { return this.c; } set celsius(v: i32) { this.c = v; }}
function main(): i32 { let t: Temp = new Temp(20); let a: i32 = t.celsius; // getter => 20 t.celsius = 22; // setter return a + t.celsius; // => 42}Read-only properties
A getter without a matching setter is read-only. Assigning to it is a compile error:
class Id { private n: i32; constructor(n: i32) { this.n = n; }
get id(): i32 { return this.n; } // no setter}
function main(): i32 { let x: Id = new Id(1); // x.id = 5; // error: 'id' has no setter return x.id; // => 1}Accessors through references
Accessors resolve on the receiver’s declared type, so they also work through parameters and nested fields — not just local variables:
class Box { private v: i32; constructor(v: i32) { this.v = v; } get value(): i32 { return this.v; }}
function readIt(b: Box): i32 { return b.value; // getter dispatched via the parameter's type}
function main(): i32 { let b: Box = new Box(42); return readIt(b); // => 42}