Jadpo is experimental and not ready for production. These docs follow the compiler's main branch as of 30 Oct 2026. What's built · Install 0.1.0
jadpo
Reference: Logic

Logic

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).

Here is a function:

example
/// 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}

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 a707efb.