Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/elfrask/cls/llms.txt

Use this file to discover all available pages before exploring further.

CLS has a full object-oriented programming system built into the language core. Classes are declared with class, use function main as the constructor, reference the current instance with me, and support single inheritance, visibility modifiers, operator overloading via magic methods, generics, and compile-time interfaces — all without a new keyword in sight.

Declaring a Class

A class body contains field declarations (var) and method definitions (function). The special method function main serves as the constructor: it is called automatically when the class is instantiated. Inside any method, me refers to the current instance — equivalent to this in other languages.
class Persona {
    var nombre: String;
    var edad: int = 0;

    function main(nombre: String, edad: int) {
        me.nombre = nombre;
        me.edad = edad;
    }

    function saludar() -> String {
        return "Hola, " + me.nombre;
    }

    static function crear(nombre: String) -> Persona {
        return Persona(nombre, 0);
    }
};
main is the constructor — not a lifecycle hook or entry-point method. It is invoked automatically the moment you instantiate the class with ClassName(args).

Instantiation

Classes are instantiated by calling the class name as if it were a function. There is no new keyword.
var p = Persona("Ana", 30);
print(p.saludar());           # → "Hola, Ana"
print(Persona.crear("Bea"));  # static method call

The me Reference

me is available inside every instance method and always points to the object on which the method was called. Use me.field to read or write instance fields, and me.method() to call other methods on the same object.
class Contador {
    var valor: int = 0;

    function incrementar() {
        me.valor = me.valor + 1;
    }

    function obtener() -> int {
        return me.valor;
    }
};

var c = Contador();
c.incrementar();
print(c.obtener());  # → 1

Static Members

Static fields and methods belong to the class itself, not to any instance. Declare them with static var or static function, and access them through the class name.
class Cuenta {
    static var tasa: float = 0.05;

    static function obtenerTasa() -> float {
        return Cuenta.tasa;
    }
};

print(Cuenta.tasa);            # → 0.05
print(Cuenta.obtenerTasa());   # → 0.05

Inheritance

CLS supports single inheritance. The primary syntax uses a colon (:); the keywords extends and parentheses (Parent) are also accepted.
class Animal {
    var name: String;

    function main(name: String) {
        me.name = name;
    }

    function speak() -> String {
        return me.name + " hace un sonido";
    }
};

# Primary syntax
class Dog: Animal {
    function speak() -> String {
        return super.speak() + " y ladra";
    }
};

# Parentheses syntax — equivalent
class Cat (Animal) {
    function speak() -> String {
        return me.name + " maúlla";
    }
};
Subclasses inherit all fields and methods from the parent. The child can override any method — accessing the parent’s original version through super.

Using super

ExpressionEffect
super.method(args)Calls the parent’s version of method, bypassing the override.
super.fieldReads a field defined in the parent class.
super.main(args)Calls the parent constructor explicitly.
class CuentaVip: Cuenta {
    function main(titular: String, saldo: float) {
        super.main(titular, saldo);   # delegate to parent constructor
    }

    function descripcion() -> String {
        return "Vip " + me.numero;    # me.numero inherited from Cuenta
    }
};

The is Operator

is tests whether an object is an instance of a given class. It returns true for the direct class and any ancestor class in the inheritance chain.
var d = Dog("Rex");

print(d is Dog);     # true  — direct instance
print(d is Animal);  # true  — inherited
print(d is String);  # false — unrelated type

Visibility Modifiers

CLS enforces access control at runtime (and at type-check time). Both fields and methods can carry a visibility modifier. Without any modifier, members are accessible from anywhere (effectively public).
ModifierAccess rule
privateOnly from inside the same class, via me. or super..
protectedFrom the class and all its subclasses. Never from outside.
publicFrom anywhere — inside the class, subclasses, and external code.
staticLives on the class itself; accessed with ClassName.member.
readonlyExternal code can read the value, but only internal code (via me.) can write it.
class Cuenta {
    private var saldo: float;
    public var titular: String;
    protected var numero: String;
    readonly var creadoEn: int;
    static var tasa: float = 0.05;

    function main(titular: String, saldo: float) {
        me.titular = titular;
        me.saldo = saldo;
        me.numero = "001-0001";
        me.creadoEn = 2026;
    }

    private function auditar() -> bool { return me.saldo >= 0; }
    public function depositar(monto: float) { me.saldo = me.saldo + monto; }
    public function verSaldo() -> float { return me.saldo; }
    protected function verNumero() -> String { return me.numero; }
    static function obtenerTasa() -> float { return Cuenta.tasa; }
};
Attempting to access a private or protected member from outside its allowed scope produces a runtime error:
var c = Cuenta("Ana", 100.0);
print(c.titular);     # OK — public

try {
    var x = c.saldo;  # ERROR — private
} catch (e) {
    print("c.saldo blocked (ok)");
};

try {
    c.creadoEn = 1999; # ERROR — readonly
} catch (e) {
    print("c.creadoEn is readonly (ok)");
};

Magic Methods

Magic methods let objects define how they respond to built-in operators, type conversions, and protocol functions like len(), print(), and for each. They follow a __name naming convention. If a magic method is absent, the interpreter falls back to default behavior without raising an error.
class Number {
    var value: int;

    function main(v: int) { me.value = v; }

    function __toString() -> String {
        return "Num(" + toString(me.value) + ")";
    }

    function __equals(other) -> bool {
        return me.value == other.value;
    }

    function __compare(other) -> int {
        if (me.value < other.value) { return -1; }
        if (me.value > other.value) { return 1; }
        return 0;
    }

    function __add(other) -> Number {
        return Number(me.value + other.value);
    }

    function __neg() -> Number {
        return Number(-me.value);
    }

    function __len() -> int {
        return len(toString(me.value));
    }

    function __get(index: int) -> int {
        return [me.value, me.value * 2, me.value * 3][index];
    }

    function __iter() -> Array {
        return [me.value, me.value + 1, me.value + 2];
    }

    function __call(x: int) -> int {
        return me.value + x;
    }
};

var a = Number(5);
var b = Number(7);

print(a);             # → "Num(5)"    — __toString
print(a == Number(5));# → true        — __equals
print(a < b);         # → true        — __compare
print(a + b);         # → Num(12)     — __add
print(-a);            # → Num(-5)     — __neg
print(len(a));        # → 1           — __len
print(a[0]);          # → 5           — __get
print(a(10));         # → 15          — __call

for each item in (a) {     # __iter
    print(item);           # 5, 6, 7
}

Full Magic Method Reference

Magic methodTriggered by
__toString()print(x), toString(x), string interpolation "$x"
__equals(other)== and != operators
__compare(other)<, <=, >, >= (return -1, 0, or 1)
__add(other)x + y
__sub(other)x - y
__mul(other)x * y
__div(other)x / y
__mod(other)x % y
__pow(other)x ** y
__neg()Unary -x
__not()Unary !x
__int()int(x)
__float()float(x)
__bool()bool(x)
__len()len(x)
__get(index)x[i] (index read)
__set(index, value)x[i] = v (index write)
__contains(value)value in x
__iter()for each item in (x) — return iterable
__next()Manual iterator advancement
__call(...)x(...) — callable object
__type()type(x) — return a custom type name string
__toJson()json.stringify(x)
__clone()User-defined clone convention (called explicitly)

Generic Classes

Classes can be parameterised with one or more type parameters declared in angle brackets. The type variable (T) can be used for field types, parameter types, and return types.
class Caja<T> {
    var contenido: T;

    function main(contenido: T) {
        me.contenido = contenido;
    }

    function obtener() -> T {
        return me.contenido;
    }
};

var cajaNum = Caja(42);
print(cajaNum.obtener());     # → 42

var cajaTxt = Caja("hola");
print(cajaTxt.obtener());     # → "hola"
At runtime, generic classes work without explicit type annotations — Caja(42) infers T = int automatically. Full static verification of Caja<String> member types is planned as a future improvement to the type checker.

Interfaces

Interfaces define a structural contract — a set of method signatures a class must satisfy. They exist only at compile time and do not generate any runtime code.
interface Printable {
    print(): void
};

interface Serializable {
    serialize(): String,
    deserialize(data: String): void
};
Use interfaces as type annotations to let the type checker verify structural compatibility across unrelated class hierarchies without requiring a shared base class.

Build docs developers (and LLMs) love