KUJO THE COURSE

THE KUJO COURSE · VERIFIED 1.3.1

Functions, callbacks, and return values

Extract decisions into small functions with explicit results.

STAGE 1 / Kujo foundations · LESSON 06

Mental model

A function defines an operation and the parameters it accepts. The caller should be able to understand what input is needed and what output means without reading every statement in the body.

Language contract

Use func name(parameters) { ... }. Arguments are positional and arity matters. An explicit return value supplies a result. Reaching the end of a function returns null; the last expression is not an implicit return value. A bare return also yields null.

Functions are values. Anonymous func(...) { ... } expressions can be passed to other functions, enabling callbacks. A closure resolves captured names from its lexical context. Treat capture behavior as Kujo behavior, not as an imported Python or JavaScript equivalence; the next stage examines it more closely.

Read the example

apply knows how to invoke an operation, while the anonymous function defines a calculation. Separating them lets a caller change the policy without rewriting the mechanism. The second function deliberately falls through to expose null.

Professional pattern

Keep domain calculations pure: pass values in, return values out. Put file reads, network requests, and printing at the application's edge. This lets tests call the calculation without granting host authority and makes later model-proposed inputs easier to validate.

Do not make a callback quietly depend on a large set of global variables. Pass context explicitly or capture only the bindings the callback needs, so its inputs remain inspectable. For a tool handler later, this distinction becomes a security concern: a tool description is not permission to access any global resource.

Common mistakes

Printing a value does not return it. A caller receiving null may indicate a missing return, not a broken arithmetic operation. Likewise, supplying extra arguments is not a portable way to attach optional context; use the exact signature or a deliberate dictionary parameter.

Working example

func apply(value, operation) { return operation(value) }
let doubled := apply(6, func(x) { return x * 2 })
func no_result() { let local := 3 }
assert_equal(doubled, 12)
assert_equal(no_result(), null)
print(doubled)

Run it

From the course repository root, use the pinned Kujo 1.3.1 runtime.

kujo check examples/06.kujo
kujo run --untrusted  examples/06.kujo

Captured output

12

Break it and diagnose it

The function requires two positional arguments. The failure concerns arity, not the arithmetic inside the function.

func add(a, b) { return a + b }
print(add(1))

kujo run --untrusted  examples/06-break.kujo

Exit status: 4. Captured diagnostic:

[KUJOVM001] [vm] Runtime Error: add expects 2 arguments, got 1
  --> 0:0


Exercise

Write a summarize(values, predicate) function. Pass two predicates that accept different values. Keep printing outside the function and test the returned summary directly.

Checkpoint

  • I use explicit return when a result is required.
  • I can pass a function as a value.
  • I can explain a callback’s inputs and captured context.

Verified 2026-09-06 · Official Kujo 1.3.1 release · Source contract · Download example