Type System & Null Safety
Autolang enforces compile-time type safety and strict null-safety invariants. The entire script is type-checked and validated before execution begins, absorbing mistakes before any external host capability is called.
Nullable vs Non-Nullable Types
Types in Autolang cannot hold null unless explicitly declared with a trailing ? (such as String? or Int?). Assigning null to a non-nullable type fails during compilation.
// Non-nullable type: cannot be assigned null
var accountId: String = "ACC-1002"
// accountId = null // Compile-time error
// Nullable type: permits null
var backupEmail: String? = null
backupEmail = "backup@enterprise.com"Safe Call Operator (?.)
Direct access on nullable instances is rejected at compile time. Use the safe call operator ?. to access properties or invoke methods. If the receiver evaluates to null, the entire call safely evaluates to null without runtime faults.
class Organization(val code: String, val parent: Organization?)
val rootOrg: Organization? = Organization("HQ", null)
val parentCode: String? = rootOrg?.parent?.code
println("Parent code: " + parentCode) // Prints nullElvis Operator (?:) with Control Flow
The Elvis operator ?: (or ??) returns the left-hand operand when non-null; otherwise, it evaluates the right-hand operand. In Autolang, the right-hand side can be an expression, a fallback default, or a control flow statement such as return, break, continue, or throw.
fun getDiscountedPrice(priceList: Map<String, Int>, itemId: String): Int {
// Early exit if the item does not exist
val basePrice = priceList[itemId] ?: return 0
return basePrice - 10
}
fun findFirstActive(candidates: Array<String?>, statusMap: Map<String, String>): String {
for (candidate in candidates) {
val candidateId = candidate ?: continue
val status = statusMap[candidateId] ?: break
if (status == "ACTIVE") {
return candidateId
}
}
return "NONE"
}Smart Casting & Non-Null Assertion
When the compiler can verify that a nullable variable is not null within a conditional branch, it automatically smart-casts the variable to its non-null counterpart. Alternatively, use the non-null assertion operator ! when you guarantee that a value cannot be null.
val authToken: String? = "tok_enterprise_99"
// Smart casting inside condition branch
if (authToken != null && authToken.length > 5) {
println("Valid token prefix: " + authToken.substr(0, 4))
}
// Forced non-null assertion
val verifiedToken: String = authToken!
println("Token active: " + verifiedToken)Type Checking (is / !is) & Casting (as)
Use is and !is to inspect dynamic runtime types or subtyping relationships. Use as to explicitly cast a value to a targeted type.
fun inspectPayload(data: Any): String {
return when (data) {
is String -> "String payload: " + data
is Int -> "Integer payload: " + data.toString()
!is Bool -> "Non-boolean structured object"
else -> "Boolean flag"
}
}
println(inspectPayload("CRM_SYNC_SUCCESS"))
println(inspectPayload(200))Type Aliases
Use typealias to declare meaningful business names for existing types, complex generic structures, or function signatures.
typealias CustomerId = String
typealias MetricsMap = Map<String, Float>
typealias AuditFilter = (String) -> Bool
val customerMap: MetricsMap = mapOf("retention" to 0.94, "churn" to 0.06)
val filterFn: AuditFilter = { key: String -> key == "retention" }
println("Retention metric: " + customerMap.get("retention"))