- Introduction
- Editor
- Get started
- Runtime / VM
Language Guide
Design-Notes
Classes & Inheritance
Autolang supports object-oriented programming using classes and single inheritance.
Primary Constructor
A primary constructor is declared in the class header.
class className(parameter1: type, ...) {
val member1: type = ...
var member2: Int?
func functionMember() {
...
}
}All parameters in primary constructor will be members of class.
You can also declare additional properties and functions inside the class body.
🚀 Performance Tip: Native Bulk Initialization
We highly recommend using the Primary Constructor for better performance.
Since members are managed by internal IDs, the compiler recognizes that a Primary Constructor is dedicated solely to member initialization. Instead of executing multiple this.field = value assignments as separate bytecode instructions in the VM, AutoLang triggers a single native call to store the entire object data in one pass.
Example
class Person(val name: String, val age: Int, val id: Int) {
// Optimized: All 3 fields are initialized natively at once
func printInfo() {
println("${name} [${id}] is ${age} years old")
}
}
val john = Person("John", 25, 1001)
john.printInfo()A class with a primary constructor cannot define a secondary constructor.
Secondary Constructor
A class can define a secondary constructor using the constructor keyword. If a class extends another class, it must use a secondary constructor.
class User extends Object {
// Slower: Executes sequential assignments
constructor(position: Vector2, name: String) {
super(position)
println(name)
}
}- A secondary constructor is required when using
extends super(...)must be calledsuper(...)must be the first statement
Late Initialization
Use the lateinit modifier to declare a non-nullable property that will be initialized later. This allows you to bypass the compiler check for immediate initialization in the constructor.
class GameEngine {
lateinit var config: String
func init() {
// Initialized later, not in constructor
config = "Loaded Config"
}
func start() {
println(config)
}
}
val engine = GameEngine()
engine.init()
engine.start()Access Modifiers
Autolang supports access control using the following 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 func deposit(amount: Int) {
balance = balance! + amount
}
private func logInternal() {
println("Internal log")
}
}
class SavingAccount extends Account {
constructor() {
super(1, 1000)
println(balance) // allowed (protected)
}
}
SavingAccount()Method Override
Use the @override modifier to override a base method.
class Animal(val name: String) {
func sound() {
}
}
class Cat extends Animal {
constructor() {
super("cat")
}
@override
func sound() {
println("Meow")
}
}
class Dog extends Animal {
constructor() {
super("dog")
}
@override
func sound() {
println("Hello guys!!!")
}
}
val dog: Animal = Dog()
val cat: Animal = Cat()
dog.sound()
cat.sound()Preventing Override
Use the @no_override annotation to prevent subclasses from overriding a specific method. This effectively makes the method "final".
class Base {
@no_override
func coreLogic() {
println("Core logic cannot be changed")
}
}
class Child extends Base {
constructor() { super() }
// Uncommenting the code below will cause a compilation error:
/*
@override
func coreLogic() {
println("Trying to change logic")
}
*/
}
val c = Child()
c.coreLogic()Static Members
Static members belong to the class, not instances.
class Person()
class X extends Person {
static val k: Int = 99
constructor() {
super()
}
}
println(X.k)Index Operator Overloading
You can define how your objects behave with the index operator [] by implementingget and set functions. This works for any class, allowing you to create custom collections or data wrappers.
class DailyTemperatures {
// Internal storage
private val temps: Array<Int> = Array<Int>()
// Adds support for: val t = obj[i]
func get(index: Int): Int {
return temps.get(index)
}
// Adds support for: obj[i] = value
func set(index: Int, value: Int) {
temps.set(index, value)
}
func add(t: Int) { temps.add(t) }
}
val data = DailyTemperatures()
data.add(30)
data.add(32)
// Syntactic sugar: Calls data.set(1, 35)
data[1] = 35
// Syntactic sugar: Calls data.get(1)
println("Temperature: ${data[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)
println(x is Animal)
println(x is Float)