Generics
Generics enable reusable, type-safe data structures and algorithms without sacrificing compile-time guarantees. Autolang supports generic classes, standalone generic functions, generic member methods, and automatic type parameter inference.
Generic Functions & Type Inference
Define generic functions by placing type parameters in angle brackets <T> before the function name. In most calls, the compiler automatically infers type arguments from the provided parameters.
// Generic identity function
fun <T> identity(value: T): T = value
// Compiler infers type parameter automatically
val number = identity(2048) // Inferred as Int
val serviceName = identity("CRM") // Inferred as String
// Multiple type parameters
fun <K, V> makeEntry(key: K, value: V): Pair<K, V> {
return key to value
}
val entry = makeEntry("AUTH_TOKEN", 99201)
println("Key: " + entry.first + ", Value: " + entry.second)Generic Classes
Classes can declare one or more type parameters in their header. Primary constructors automatically inherit and infer these type parameters.
class ServiceResponse<T>(val status: Int, val payload: T, val ok: Bool = true) {
fun getPayload(): T = this.payload
}
// Inferred from argument
val intResponse = ServiceResponse(200, 42)
println("Status: " + intResponse.status + ", Payload: " + intResponse.getPayload())
// Explicit generic instantiation
val stringResponse = ServiceResponse<String>(200, "Operation Completed")
println("Message: " + stringResponse.getPayload())Generic Member Methods & Static Methods
Classes (both generic and non-generic) can define member methods and static functions with their own independent type parameters.
class DataTransformer {
// Generic member method on a standard class
fun <T> wrapInArray(item: T): Array<T> {
val list: Array<T> = []
list.add(item)
return list
}
// Generic static method
static fun <R> echoStatic(x: R): R {
return x
}
}
val transformer = DataTransformer()
val stringArray = transformer.wrapInArray("enterprise_payload")
println("Array length: " + stringArray.size()) // 1
val echoed = DataTransformer.echoStatic<Int>(500)
println("Echoed: " + echoed) // 500Type Constraints (Upper Bounds)
Constrain generic type parameters using the colon syntax (<T: BaseClass>). This guarantees that callers can only supply types that extend or implement the specified base class.
class BaseEntity(val entityId: String) {
fun identifier(): String = this.entityId
}
class InvoiceEntity extends BaseEntity {
constructor(id: String) { super(id) }
}
// Generic function constrained to BaseEntity
fun <T: BaseEntity> logEntity(entity: T): String {
return "Entity audit: " + entity.identifier()
}
val invoice = InvoiceEntity("INV-2026")
println(logEntity(invoice)) // Entity audit: INV-2026