Skip to content

Struct Hooks

Structs can define internal hooks in impl.

These hooks let custom structs behave more like built-in values.

HookDescription
__string__Controls string conversion.
__clone__Controls clone behavior.
__value__Returns an underlying primitive value.
__get__Enables indexed reads like value[key].
__set__Enables indexed writes like value[key] = other.
__iterate__Enables for item in value.
$convoutConverts public fields into dictionary-like output.

Define __string__ to control string conversion.

struct Point {
x: int
y: int
}
impl Point {
fn __string__(self: Point) string {
return "Point(" + string(self.x) + ", " + string(self.y) + ")"
}
}
let point = Point()
point.x = 10
point.y = 20
println(string(point))

Define __clone__ to control how an object is copied.

struct User {
name: string
roles: []string
}
impl User {
fn __clone__(self: User) User {
let copy = User()
copy.name = self.name
copy.roles = clone(self.roles)
return copy
}
}
let user = User()
let copied = clone(user)

Use clone(value) in normal code. Do not call __clone__ directly unless you are working on internals.

Define __value__ to expose an underlying value.

This is useful when a struct wraps a primitive value.

struct Counter {
value: int
}
impl Counter {
fn __value__(self: Counter) any {
return self.value
}
}
let counter = Counter()
counter.value = 10
println(valueof(counter))

valueof() is the readable way to get the underlying value.

Some standard types use this pattern. For example, time values can expose an integer value so operations can use the underlying numeric representation.

let raw = valueof(time.now())

Define __get__ and __set__ to make a struct indexable.

struct Store {
data: dict[string, any]
}
impl Store {
fn __get__(self: Store, key: string) any {
return self.data[key]
}
fn __set__(self: Store, key: string, value: any) void {
self.data[key] = value
}
}
let store = Store()
store.data = {}
store["name"] = "Nubo"
println(store["name"])

Define __iterate__ to make a struct usable in for loops.

import iter from "@std/iter"
struct CountTo {
stop: int
}
impl CountTo {
fn __iterate__(self: CountTo) iter.Iterator {
let current = 0
return iter.Iterator(fn() iter.Progress {
if current >= self.stop {
return iter.End
}
let value = current
current = current + 1
return iter.Progress(value, value)
})
}
}
let counter = CountTo()
counter.stop = 3
for i in counter {
println(i)
}

Nubo automatically adds $convout to struct instances.

It converts public fields into a dictionary-like output and skips private fields.

struct User {
name: string
private password: string
}

Only public fields are included in conversion output.

Use hooks to make custom types integrate with language syntax.

Use normal functions for normal behavior.

impl User {
fn greet(self: User) string {
return "Hello, " + self.name
}
}

Only use internal names when you need language-level behavior.