Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 5 Nov 2026. What's built · Install 0.3.0
jadpo
ReferenceLogic

LanguageLogic

Functions and actions

On this page

You write behaviour in three kinds of callable:

  • A function is pure: it works out a result from its arguments and nothing else.
  • An action is an operation of your app. It may read and write stored data, call outside services and call other actions.
  • A query reads stored data and never changes it (Named queries).

An action that writes nothing, emits nothing and makes no changing call, itself or through any action it calls, is read-only. You don't mark it: the compiler works it out from what the action does. A read-only action can answer a GET, as a query can (A GET that runs an action).

Here is a function. Save this as main.jadpo and run jadpo test main.jadpo:

example
type Stock = Int {    min: 0}type Quantity = Int {    min: 1    max: 1000}/// Total for one order line before discounts.function stock_needed(per_pack: Stock, packs: Quantity) -> Stock {    var total: Stock = Stock(per_pack * packs)    return total}test "six packs of four need 24" {    assert stock_needed(4, 6) == 24}

Int is built in. Stock, Quantity and stock_needed are defined here.

And an action, which loads a todo, changes it and returns a view of it:

example
action complete_todo(todo_id: Todo.id) fails TodoNotFound -> TodoView {    var todo: Todo = attempt Todo.get(todo_id)    var done: Todo = Todo.update(todo) {        set: {            status: TodoStatus.done        }    }    return TodoView(done)}

Each kind may call only some of the others:

Caller May call May not
function functions, library functions, the standard library actions, queries, stored data, outside services, clock.now
query functions and queries actions, writes
action functions, queries and actions
A route's run: one action a function or query directly (What a route runs)

A function may still fail: it can declare fails and reject (Failures). There is no async, await or promise: every call finishes before the caller carries on.

Signatures and settings

Parameters are positional, and every one has a type. The result type follows ->, and fails comes before it. A callable that returns nothing returns Unit. Parameters have no defaults.

example
action reschedule(todo_id: Todo.id, due_at: DueAt) fails TodoNotFound, DueDateInPast -> TodoView {    var todo: Todo = attempt Todo.get(todo_id)    ...}

Your own callables are called with positional arguments. Named arguments exist only for standard-library operations, such as temporal.resolve(date: d, zone: z, ...).

The whole signature is on the header line, and an action has no settings, because the safe choice is already the default:

  • every action is all-or-nothing;
  • every write checks that no one else changed the record since it was read;
  • every read is current.

All-or-nothing actions and concurrent changes has the details. Who may call an action is set by Policy, not by the action.

When a header is too long, the formatter puts one parameter on each line and keeps fails and -> after the closing bracket.

Calling

What comes before the dot names the owner of what you call. Inside your own domain (a business area of your app, a folder under domains/; see Project layout), you call its actions and queries by name alone. A helper function used only in its own file is called the same way.

A helper that several files share lives in a library, a named group of functions and constants, and is called through it, as the standard library is. Another domain's public actions are called through that domain's name.

example
library rounding {    function half_even(amount: ItemPrice) -> ItemPrice { ... }}var total: ItemPrice = rounding.half_even(subtotal)var line: Stock = stock_needed(per_pack, packs)var stock: Reservation = attempt inventory.reserve_for_cart(cart)var todo: Todo = attempt Todo.get(todo_id)var local: ZonedTime = temporal.in_zone(at, zone)

In order, those calls are: a function in the rounding library, a helper in this file, an action of the inventory domain, an operation every entity gets, and the standard library.

A library holds only functions and constants (see Constants).

Markdown for agents: /docs/functions-and-actions.md.Built from Jadpo main at aee2e8f.