Classes & OOP
Object-oriented programming in Soli: classes, inheritance, interfaces, and static members.
Basic Class Definition
class
Defines a class with properties and methods.
class Person {
name: String;
age: Int;
email: String;
new(name: String, age: Int, email: String = null) {
this.name = name;
this.age = age;
this.email = email ?? "";
}
fn greet() -> String {
return "Hello, I'm " + this.name;
}
fn introduce() -> String {
let intro = "Hi, I'm " + this.name + " and I'm " + str(this.age) + " years old";
if (this.email != "") {
intro = intro + ". You can reach me at " + this.email;
}
return intro;
}
fn have_birthday() {
this.age = this.age + 1;
}
}
// Creating instances
let alice = new Person("Alice", 30);
let bob = new Person("Bob", 25, "[email protected]");
// Using instances
print(alice.greet()); // "Hello, I'm Alice"
print(bob.introduce()); // "Hi, I'm Bob and I'm 25 years old..."
alice.have_birthday();
print(alice.age); // 31
Inheritance
extends
Create a subclass that inherits from a parent class.
// Base class
class Animal {
name: String;
age: Int;
new(name: String, age: Int) {
this.name = name;
this.age = age;
}
fn speak() -> String {
return this.name + " makes a sound";
}
fn get_info() -> String {
return this.name + " is " + str(this.age) + " years old";
}
}
// Subclass
class Dog extends Animal {
breed: String;
new(name: String, age: Int, breed: String) {
super(name, age);
this.breed = breed;
}
// Override method
fn speak() -> String {
return this.name + " barks!";
}
// Subclass-specific method
fn fetch() -> String {
return this.name + " fetches the ball!";
}
}
// Using inheritance
let dog = new Dog("Buddy", 3, "Golden Retriever");
print(dog.speak()); // "Buddy barks!"
print(dog.get_info()); // "Buddy is 3 years old"
print(dog.fetch()); // "Buddy fetches the ball!"
print(dog.breed); // "Golden Retriever"
Interfaces
interface / implements
Define contracts that classes must implement.
// Define an interface
interface Drawable {
fn draw() -> String;
fn get_color() -> String;
}
// Another interface
interface Resizable {
fn resize(width: Float, height: Float);
fn get_dimensions() -> {width: Float, height: Float};
}
// Class implementing multiple interfaces
class Circle implements Drawable, Resizable {
radius: Float;
color: String;
new(radius: Float, color: String) {
this.radius = radius;
this.color = color;
}
fn draw() -> String {
return "Circle with radius " + str(this.radius) + " and color " + this.color;
}
fn get_color() -> String {
return this.color;
}
fn resize(width: Float, height: Float) {
this.radius = width / 2;
}
fn get_dimensions() -> {width: Float, height: Float} {
return {"width": this.radius * 2, "height": this.radius * 2};
}
}
// Using interfaces
let shapes: Drawable[] = [
new Circle(5.0, "red"),
];
for (shape in shapes) {
print(shape.draw()); // Polymorphic call
}
Visibility Modifiers
| Modifier | Access |
|---|---|
| public | Accessible from anywhere (default) |
| private | Intended for use only within the class |
| protected | Intended for use within class and subclasses |
Note: Visibility modifiers are currently parsed for documentation purposes but not enforced at runtime.
class BankAccount {
public account_number: String;
private balance: Float;
new(account_number: String, initial_deposit: Float) {
this.account_number = account_number;
this.balance = initial_deposit;
}
public fn deposit(amount: Float) -> Bool {
if (this.validate_amount(amount)) {
this.balance = this.balance + amount;
return true;
}
return false;
}
public fn get_balance() -> Float {
return this.balance;
}
private fn validate_amount(amount: Float) -> Bool {
return amount > 0;
}
}
let account = new BankAccount("123456789", 1000.0);
account.deposit(500.0); // Works - public method
print(account.get_balance()); // 1500.0
Static Members
static
Properties and methods that belong to the class, not instances.
class MathUtils {
static PI: Float = 3.14159265359;
static E: Float = 2.71828182846;
static fn square(x: Float) -> Float {
return x * x;
}
static fn cube(x: Float) -> Float {
return x * x * x;
}
static fn max(a: Float, b: Float) -> Float {
return a > b ? a : b;
}
static fn clamp(value: Float, min_val: Float, max_val: Float) -> Float {
if (value < min_val) {
return min_val;
}
if (value > max_val) {
return max_val;
}
return value;
}
}
// Using static members
print(MathUtils.PI); // 3.14159265359
print(MathUtils.square(4.0)); // 16.0
print(MathUtils.cube(3.0)); // 27.0
print(MathUtils.clamp(150, 0, 100)); // 100