Classes & OOP

Quartz features a comprehensive object-oriented programming system inspired by Java and C++, with clean, modern syntax that prioritizes developer experience.

Class Declaration

Define a class using the class keyword:

class Person {
// Fields (instance variables)
string name;
int age;
bool active;

// Methods (instance functions)
fn greet() {
io.out.println("Hello, I'm", name);
}

fn haveBirthday() {
age += 1;
io.out.println(name, "is now", age);
}
}

Object Creation

Create instances using the new keyword:

let person = new Person();

// Set field values
person.name = "Alice";
person.age = 30;
person.active = true;

// Call methods
person.greet();        // "Hello, I'm Alice"
person.haveBirthday(); // "Alice is now 31"

Fields

Fields are instance variables that belong to each object:

class Rectangle {
double width;
double height;
string color;
}

let rect = new Rectangle();
rect.width = 10.0;
rect.height = 5.0;
rect.color = "blue";

io.out.println("Width:", rect.width);  // 10.0

Supported Field Types

Methods

Methods are functions that belong to a class:

class Calculator {
int value;

// Method with no return value
fn reset() {
value = 0;
}

// Method with parameters
fn add(n: int) {
value += n;
}

// Method with return value
fn getValue() -> int {
return value;
}

// Method with multiple parameters
fn multiply(a: int, b: int) -> int {
return a * b;
}
}

let calc = new Calculator();
calc.reset();
calc.add(10);
calc.add(5);
io.out.println("Value:", calc.getValue());  // 15
io.out.println("3 * 4 =", calc.multiply(3, 4));  // 12

Return Statements

Use return to exit a method and optionally return a value:

class Math {
fn abs(x: int) -> int {
if (x < 0) {
return -x;  // Early return
}
return x;
}

fn isEven(n: int) -> bool {
return n % 2 == 0;
}

fn doSomething() {
// Void methods can omit return
io.out.println("Done");
}
}

Inheritance

Create class hierarchies using extends:

class Animal {
string name;
int age;

fn speak() {
io.out.println("Animal sound");
}

fn describe() {
io.out.println(name, "is", age, "years old");
}
}

class Dog extends Animal {
string breed;

fn speak() {
io.out.println("Woof! Woof!");
}

fn fetch() {
io.out.println(name, "fetches the ball");
}
}

class Cat extends Animal {
bool indoor;

fn speak() {
io.out.println("Meow!");
}

fn purr() {
io.out.println(name, "purrs contentedly");
}
}

// Usage
let dog = new Dog();
dog.name = "Buddy";
dog.age = 3;
dog.breed = "Golden Retriever";

dog.describe();  // "Buddy is 3 years old"
dog.speak();     // "Woof! Woof!"
dog.fetch();     // "Buddy fetches the ball"

Access Modifiers

Quartz supports visibility modifiers for encapsulation:

class BankAccount {
public string owner;
private double balance;
protected string accountId;

public fn deposit(amount: double) {
if (amount > 0) {
balance += amount;
}
}

public fn getBalance() -> double {
return balance;
}

private fn generateId() -> string {
return "ACC-12345";
}
}
Modifier Visibility
`public` Accessible from anywhere
`private` Accessible only within the class
`protected` Accessible within class and subclasses

Static Methods

Static methods belong to the class, not instances:

class MathUtils {
static fn max(a: int, b: int) -> int {
if (a > b) {
return a;
}
return b;
}

static fn min(a: int, b: int) -> int {
if (a < b) {
return a;
}
return b;
}
}

// Call without creating an instance
let maximum = MathUtils.max(10, 20);  // 20

Composition

Classes can contain instances of other classes:

class Point {
double x;
double y;

fn distanceTo(other: Point) -> double {
let dx = other.x - x;
let dy = other.y - y;
return math.sqrt(dx * dx + dy * dy);
}
}

class Circle {
Point center;
double radius;

fn area() -> double {
return 3.14159 * radius * radius;
}

fn contains(point: Point) -> bool {
return center.distanceTo(point) <= radius;
}
}

let circle = new Circle();
circle.center = new Point();
circle.center.x = 0.0;
circle.center.y = 0.0;
circle.radius = 5.0;

io.out.println("Area:", circle.area());

Complete Example

import system.io as io;
import system.math as math;

class Shape {
string name;
string color;

fn describe() {
io.out.println("A", color, name);
}
}

class Circle extends Shape {
double radius;

fn area() -> double {
return 3.14159 * radius * radius;
}

fn circumference() -> double {
return 2.0 * 3.14159 * radius;
}
}

class Rectangle extends Shape {
double width;
double height;

fn area() -> double {
return width * height;
}

fn perimeter() -> double {
return 2.0 * (width + height);
}

fn isSquare() -> bool {
return width == height;
}
}

// Create shapes
let circle = new Circle();
circle.name = "Circle";
circle.color = "red";
circle.radius = 5.0;

let rect = new Rectangle();
rect.name = "Rectangle";
rect.color = "blue";
rect.width = 10.0;
rect.height = 5.0;

// Use them
circle.describe();
io.out.println("Area:", circle.area());
io.out.println("Circumference:", circle.circumference());

io.out.println("");

rect.describe();
io.out.println("Area:", rect.area());
io.out.println("Perimeter:", rect.perimeter());
io.out.println("Is square:", rect.isSquare());

Best Practices