Ovum is a strongly statically typed, single-threaded language focused on safety, clarity, and performance. It uses Kotlin-like syntax, immutability by default, a GC + JIT VM, interface-based polymorphism, and support for pure functions and functional objects.
- Contribute: see
CONTRIBUTING.md. - Project docs: Online.
- Full language reference: Online.
- Memory safety via GC; no manual memory management.
- Immutable by default; explicit mutation with
var. - Pure functions (
pure) are side-effect free and may be cached on VM level. - Interface-based polymorphism; no class inheritance.
- Explicit
unsafe { ... }for low-level operations. - Minimal, predictable syntax; no user-defined operators.
- No generics/templates, only ad-hoc and subclass polymorphism.
- Files:
.ovum. Names: PascalCase for types/methods. - Functions:
fun Name(a: T): U { ... }; pure:pure fun .... - Classes:
class Name implements IFace { ... }; interfaces:interface IFace { ... }. - Fields:
val(immutable) orvar(mutable); access modifiers are mandatory. - Namespaces:
::(e.g.,sys::Print). Basic preprocessor:#import,#define,#ifdef…
Types and Nullability
- Fundamental types:
int,float,byte,char,bool,pointer(value types, not nullable, not Objects) - Primitive reference types:
Int,Float,Byte,Char,Bool,Pointer(reference wrappers, nullable, Objects) - Implicit conversion: Literals convert to primitives (
val count: Int = 0) - Nullable types: Append
?to reference types only (e.g.,Int?,String?) - Safe call
?., Elvis?:for null handling - Type test
is, castas(downcast yields nullable type) - Copy assignment
:=for deep copying reference types
if/else,while,for (x in xs).return,break,continue; nogoto.
- Arithmetic:
+ - * / % - Comparison:
== != < <= > >= - Boolean:
&& || ! ^(short‑circuit&&/||). - Assignment:
=(reference assignment),:=(copy assignment) - Member/calls:
. ()and safe?. - Null handling:
?. ?: - Type ops:
as,is - Namespace:
::
- Classes implement interfaces; no class inheritance.
- Methods declare access; support
overrideandpure. - Optional destructor; called by GC (manual calls are unsafe).
- Classes or interfaces can define a special
callmember to be callable. - Function literals can coerce to an interface exposing a compatible
call.
- Pipeline:
.ovum→ bytecode → Ovum VM. - GC for memory safety; JIT compiles hot paths.
- Single‑threaded execution model.
- Architectures: amd64, arm64. Numeric widths:
int8 bytes,float8 bytes. - Entry point:
Main(args: StringArray): Int.
Build & Run (conceptual): write .ovum, compile (parse, type‑check, enforce const/pure), run on VM (JIT + GC).
sys::Print(msg: String): Voidsys::Time(): Intsys::Sleep(ms: Int): Voidsys::Exit(code: Int): Never- FFI:
sys::Interope(dllName, functionName, input: ByteArray, output: ByteArray): Int(unsafe)
Only inside unsafe { ... }:
- Global
varandstatic varwrites. - Const/mutable casts;
pointer, address‑of, dereference. - Manual destructor calls.
sys::Interope; casting any value to (const or mutable)ByteArray.
Bytecode is the intermediate representation of the Ovum program. It is generated by the compiler and executed by the Ovum VM.
Ovum Bytecode:
// Simple program that prints numbers 1 to 5
function _Global_Main_StringArray {
PushInt 1
SetLocal 1
while {
LoadLocal 1
PushInt 5
IntLessEqual
} then {
LoadLocal 1
CallConstructor Int
Call _Int_ToString_<C>
PrintLine
LoadLocal 1
PushInt 1
IntAdd
SetLocal 1
}
PushInt 0
Return
}
Ovum Source Code:
fun Main(args: StringArray): Int {
var i: int = 1
while (i <= 5) {
sys::PrintLine(Int(i).ToString())
i = i + 1
}
return 0
}
// .ovum file
fun Main(args: StringArray): Int {
val count: Int = args.Length() // Built-in returns Int
sys::Print("Args count: " + count.ToString())
return 0 // Implicit conversion from literal
}
pure fun Fib(n: int): int {
if (n <= 1) return n
val fib1: int = Fib(n - 1)
val fib2: int = Fib(n - 2)
return fib1 + fib2
}
fun DemoCasts(obj: Object): Void {
if (obj is Point) {
val p: Point? = obj as Point
if (p != null) {
val nonNullP: Point = p ?: Point(0, 0) // Use Elvis operator
sys::Print(nonNullP.ToString())
}
}
// Bool cast
val b1: Bool = 0 as bool // false
val b2: Bool = 42 as bool // true
val b3: Bool = obj as bool // always true
val b4: Bool = (obj as Point) as bool // true if obj is a Point
// Unsafe: raw byte views
unsafe {
val bytesConst: ByteArray = (obj as ByteArray)
val bytesMut : ByteArray = (obj as var ByteArray)
}
}
interface CustomFunctional {
call(a: Int?, b: Int?): Int
}
class DefinedFunctional {
public var Multiplier: Int
public fun DefinedFunctional(multiplier: Int): DefinedFunctional {
this.Multiplier = multiplier
return this
}
public call(secondMultiplier: Int): Int = fun(secondMultiplier: Int): Int {
return Multiplier * secondMultiplier
}
}
val AddNullable: CustomFunctional = pure fun(a: Int?, b: Int?): Int {
val aVal: int = a ?: 0 // Implicit conversion from Int? to int
val bVal: int = b ?: 0
return Int(aVal + bVal) // Implicit conversion from int to Int
}
fun Main(args: StringArray): Int {
// Constructor call then functional call via `call`
return AddNullable(2, DefinedFunctional(-1)(2)) // Implicit conversion from literals
}
// Complete Ovum program demonstrating key features
interface ICalculator {
fun Calculate(a: Int, b: Int): Int
}
class Adder implements ICalculator {
public override fun Calculate(a: Int, b: Int): Int {
return a + b
}
}
class Multiplier implements ICalculator {
public override fun Calculate(a: Int, b: Int): Int {
return a * b
}
}
pure fun ProcessNumbers(calc: ICalculator, numbers: IntArray): int {
var result: int = 0
for (num in numbers) {
val calcResult: Int = calc.Calculate(num, 2) // Implicit conversion from literal
result = result + calcResult // Implicit conversion
}
return result
}
fun Main(args: StringArray): int {
val numbers: IntArray = IntArray(3)
numbers[0] := 5 // Implicit conversion from literal
numbers[1] := 10
numbers[2] := 15
val adder: ICalculator = Adder()
val multiplier: ICalculator = Multiplier()
val sumResult: int = ProcessNumbers(adder, numbers)
val productResult: int = ProcessNumbers(multiplier, numbers)
sys::Print("Sum result: " + Int(sumResult).ToString())
sys::Print("Product result: " + Int(productResult).ToString())
return 0 // Implicit conversion from literal
}