Classes & Inheritance
Autolang supports object-oriented programming using classes and single inheritance.
Primary Constructor
A primary constructor is declared directly in the class header. All parameters become members of the class automatically. You can also declare additional properties and functions in the class body.
class Person(val name: String, val age: Int, val id: Int) {
// Optimized: All 3 fields are initialized natively at once
fun printInfo() {
println("${name} [${id}] is ${age} years old")
}
}
val john = Person("John", 25, 1001)
john.printInfo()๐ Performance Tip
We highly recommend using the Primary Constructor for better performance. The compiler recognizes it as a dedicated initialization path and triggers a single native call to store all object data in one pass โ instead of sequential assignments.
Secondary Constructor
Use the constructor keyword when you need custom initialization logic or when a class extends another. super() must be the first statement.
class Vector2(val x: Float, val y: Float)
class User extends Vector2 {
constructor(x: Float, y: Float, name: String) {
super(x, y)
println("User ${name} created at ${x}, ${y}")
}
}
User(10.0, 20.0, "Alice")- A secondary constructor is required when using
extends super(...)must be called and must be the first statement
Late Initialization
Use the lateinit modifier to declare a non-nullable property that will be initialized later, bypassing the compiler check for immediate initialization.
class GameEngine {
lateinit var config: String
fun init() {
config = "Loaded Config"
}
fun start() {
println(config)
}
}
val engine = GameEngine()
engine.init()
engine.start()Access Modifiers
Control member visibility with access modifiers:
- public โ accessible everywhere (default)
- private โ accessible only inside the same class
- protected โ accessible inside the class and its subclasses
class Account {
private var id: Int?
protected var balance: Int?
constructor(id: Int, balance: Int) {
this.id = id
this.balance = balance
}
public fun deposit(amount: Int) {
balance = balance! + amount
}
}
class SavingAccount extends Account {
constructor() {
super(1, 1000)
println(balance) // allowed (protected)
}
}
SavingAccount()Method Override
Use @override to override a base method. Use @no_override to prevent subclasses from overriding a method (makes it "final").
class Animal(val name: String) {
fun sound() { }
}
class Cat extends Animal {
constructor() { super("cat") }
@override
fun sound() { println("Meow") }
}
class Dog extends Animal {
constructor() { super("dog") }
@override
fun sound() { println("Woof") }
}
val dog: Animal = Dog()
val cat: Animal = Cat()
dog.sound()
cat.sound()Static Members
Static members belong to the class itself, not to any instance. Access them via ClassName.member.
class X extends Person {
static val k: Int = 99
constructor() {
super()
}
}
class Person()
println(X.k)Index Operator Overloading
Define get and set functions to make your class support the [] index operator.
class DailyTemperatures {
private val temps: Array<Int> = Array<Int>()
fun get(index: Int): Int = temps.get(index)
fun set(index: Int, value: Int) { temps.set(index, value) }
fun add(t: Int) { temps.add(t) }
}
val data = DailyTemperatures()
data.add(30)
data.add(32)
data[1] = 35 // calls data.set(1, 35)
println("Temp: ${data[1]}") // calls data.get(1)Type Checking
Use the is operator for runtime type checking.
class Animal()
class Cat extends Animal {
constructor(){ super() }
}
class Dog extends Animal {
constructor(){ super() }
}
val x = Cat()
println(x is Cat) // true
println(x is Animal) // true
println(x is Float) // false