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
Objectbase 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