Skip to main content
Version: 🚧 Alpha 🚧

Inheritance

Declaring a Parent Class​

Every class that does not declare an explicit parent extends the built-in root class object. Use parent: to declare inheritance:

class vehicle {
string name <- "vehicle";
float speed <- 0.0;
float max_speed <- 120.0;
float distance_km <- 0.0;

float move() {
distance_km <- distance_km + speed;
return speed;
}

string summary() {
return "[vehicle] " + name + " speed=" + (speed with_precision 1);
}
}

Child Class with parent:​

A child class inherits all attributes and actions from its parent:

class car parent: vehicle {

string name <- "car"; // override parent default
float fuel <- 50.0; // new attribute
float consumption_per_km <- 0.08; // new attribute

// Override the parent's move() with custom logic
float move() {
if fuel <= 0.0 {
speed <- 0.0;
return 0.0; // out of fuel — can't move
}
float d <- super.move(); // parent handles distance
fuel <- max(0.0, fuel - d * consumption_per_km); // consume fuel
return d;
}

// Override summary() to append fuel info
string summary() {
return super.summary() + " fuel=" + (fuel with_precision 1) + "L";
}

action refuel(float capacity) {
fuel <- capacity;
}
}

Key Points​

  • parent: ClassName makes the new class extend that class.
  • super.action(args) calls the parent's version of a typed action (one that returns a value).
  • invoke action(args) calls the parent's version of a void procedure (action with no return).
  • Redefining an action with the same signature overrides it (dynamic dispatch).

Second Child with Same Parent​

Another child can extend the same parent with different behavior:

class bicycle parent: vehicle {

string name <- "bicycle";
float max_speed <- 30.0; // override parent max
string rider <- "nobody"; // new attribute

// Does NOT override move() — the parent implementation is used as-is.
// Only overrides summary().
string summary() {
return super.summary() + " rider=" + rider;
}
}

Multi-Level Inheritance​

A child can extend another child, creating a hierarchy:

class sports_car parent: car { // car extends vehicle — so sports_car extends both

string name <- "sports_car";
float max_speed <- 250.0; // override car's max_speed
bool turbo_active <- false;
float boost_factor <- 1.5;

// Override car's move() (which itself calls vehicle.move())
float move() {
if turbo_active {
float normal_speed <- speed;
speed <- min(speed * boost_factor, max_speed);
float d <- super.move(); // car.move() checks fuel → calls vehicle.move()
speed <- normal_speed; // restore
return d;
}
return super.move();
}

// Override car's summary() (calling super.summary() which already includes vehicle info)
string summary() {
return super.summary() + " turbo=" + turbo_active;
}
}

The call chain for sports_car.move() when turbo is active:

  1. sports_car.move() → calls super.move()
  2. car.move() → calls super.move()
  3. vehicle.move() → the base implementation that updates distance

Runtime Type Testing with is​

The is operator tests whether an object is an instance of a class or any of its subclasses:

car c <- car();
sports_car sc <- sports_car();
bicycle b <- bicycle();

c is car; // true
c is vehicle; // true (parent)
sc is sports_car; // true
sc is car; // true (sc extends car, which extends vehicle)
sc is vehicle; // true (transitive)
b is car; // false (sibling — both extend vehicle but are unrelated)

Polymorphic Lists​

An object typed as the parent class can hold any subtype object:

list<vehicle> fleet <- [c, b, sc];

loop v over: fleet {
v.move(); // dispatches to the actual object's overridden move()
v.accelerate(20.0); // shared inherited action — same for all
write v.summary(); // dispatches to each class's overridden summary()
}

Selecting Objects by Type​

Use the select keyword with is to filter:

list<vehicle> fleet <- [c, b, sc];

// Get only cars (and subclasses like sports_car)
list<vehicle> only_cars <- fleet select (each is car);
write only_cars collect each.name; // ["sedan", "gt500"]

Example: Full Model​

class vehicle {
string name <- "vehicle";
float speed <- 0.0;
float max_speed <- 120.0;
float distance_km <- 0.0;

float move() {
distance_km <- distance_km + speed;
return speed;
}

string summary() {
return "[vehicle] " + name + " speed=" + (speed with_precision 1);
}
}

class car parent: vehicle {
string name <- "car";
float fuel <- 50.0;
float consumption_per_km <- 0.08;

float move() {
if fuel <= 0.0 {
speed <- 0.0;
return 0.0;
}
float d <- super.move();
fuel <- max(0.0, fuel - d * consumption_per_km);
return d;
}

string summary() {
return super.summary() + " fuel=" + (fuel with_precision 1);
}
}

global {
init {
car c <- car(name: "sedan", speed: 80.0, fuel: 40.0, max_speed: 180.0);
bicycle b <- bicycle(name: "city-bike", speed: 15.0, rider: "Alice");

// Polymorphic dispatch
list<vehicle> fleet <- [c, b];

loop times: 5 {
loop v over: fleet {
v.move();
}
}
loop v over: fleet {
write v.summary(); // calls overridden summary per type
}

// Type filtering
list<vehicle> cars <- fleet select (each is car);
write "Cars: " + cars collect each.name;
}
}

experiment Inheritance title: "Inheritance" type: gui {}

Key Takeaways​

FeatureSyntax
Inherit from a classclass Child parent: Parent {
Override an attributeRedefine it in the child with a new default value
Override a typed actionRedefine with the same return type and parameters
Call parent actionsuper.method() returns the parent's return value
Test object typeobj is ClassName returns true for the class or any subclass
Polymorphic listlist<Parent> items <- [child1, child2];