Kyro features a dynamic, prototype-flexible Object-Oriented Programming model inspired by Python and Smalltalk. In Kyro:

  • Everything is an Object: Primitives (numbers, strings, lists, dicts), functions, and class definitions themselves inherit from a root Object base class.
  • Dynamic Attributes: Classes and instances can attach attributes at runtime without rigid pre-declarations.
  • Multiple Inheritance: Classes can inherit from multiple parent classes using comma separation (< Parent1, Parent2).
  • Rich Operator Overloading & Hooks: Deep customization using magic methods (dunders) like __add__, __getattribute__, __call__, and __getitem__.

1. Type Hierarchy & Base Object

All values in Kyro inherit from Object.

                   Object
                  /   |   \
             Class   List  Number ... (User Classes)

Checking Types with is_instance

Use the builtin is_instance(item, Class) function to inspect inheritance:

class Animal {}
class Dog < Animal {}

var d = Dog();

echo is_instance(d, Dog);    // true
echo is_instance(d, Animal); // true
echo is_instance(d, Object); // true
echo is_instance(d, Class);  // false (d is an instance, not a Class)

echo is_instance(Dog, Class);  // true (Dog is a Class definition)
echo is_instance(Dog, Object); // true (Class definitions are Objects too)

2. Classes & Instantiation

Defining a Class & Constructor (__init__)

Instantiating a class invokes __init__(self, ...) if defined.

class User {
    fn __init__(self, username, email) {
        self.username = username;
        self.email = email;
    }

    fn greet(self) {
        return "Hello, " + self.username;
    }
}

var user = User("alice", "alice@example.com");
echo user.greet(); // Output: Hello, alice

Dynamic Instance Fields

Any field can be added to an instance dynamically:

var u = User("bob", "bob@example.com");
u.age = 25; // Dynamically attached field
echo u.age; // Output: 25

3. Multiple Inheritance & super

Classes inherit methods and fields using the < symbol. Kyro supports Multiple Inheritance by separating parent classes with commas.

class Flyer {
    fn fly(self) {
        return "flying high in the sky";
    }
}

class Swimmer {
    fn swim(self) {
        return "swimming in the water";
    }
}

// Inherits methods from both Flyer and Swimmer
class Duck < Flyer, Swimmer {}

var d = Duck();
echo d.fly();  // Output: flying high in the sky
echo d.swim(); // Output: swimming in the water

4. Callable Instances (__call__)

Implement __call__(self, ...) to make class instances callable directly like functions:

class Multiplier {
    fn __init__(self, factor) {
        self.factor = factor;
    }

    fn __call__(self, value) {
        return value * self.factor;
    }
}

var double = Multiplier(2);
echo double(10); // Output: 20

5. The property Keyword (Getters)

Properties behave like methods but are accessed like variables without parentheses.

class Circle {
    fn __init__(self, radius) {
        self.radius = radius;
    }

    property area(self) {
        return 3.14159 * self.radius * self.radius;
    }
}

var c = Circle(5);
echo c.area; // Output: 78.53975

6. Attribute Interception (__getattribute__ & __setattribute__)

To access or write raw instance attributes inside interceptor hooks without triggering infinite recursion, use super.__getattribute__(name) and super.__setattribute__(name, value).

class Main {
    var h = 1;

    fn __getattribute__(self, name) {
        if (name == "h") {
            return super.__getattribute__("h") + 1;
        }
        return super.__getattribute__(name);
    }
}

var m = Main();
echo m.h; // Output: 2

7. Subscript Indexing (__getitem__ & __setitem__)

Enable bracket indexing (obj[key] and obj[key] = val) on custom class instances:

class CustomMap {
    fn __init__(self) {
        self.data = {};
    }

    fn __getitem__(self, key) {
        return self.data.get(key, "default");
    }

    fn __setitem__(self, key, value) {
        self.data[key] = value;
    }
}

var map = CustomMap();
map["a"] = 10;
echo map["a"]; // Output: 10