Reference

std/core/control

std/core/src/control.trb

Control structures that are ordinary functions. Only constructs that bind names (const, fn, type, ...) or jump (if, match, for, while) are built in.

fn do

fn do<Value>(body: () => Value): Value

Evaluates a block immediately: const x = do { ... }

fn unless

fn unless(condition: Bool, body: () => Void)

Runs the block unless the condition holds: if !condition { ... }, for a guard that reads better negated.

fn retry

fn retry<Value, Failure>(times: Int, action: () => Result<Value, Failure>): Result<Value, Failure>

const response = retry 3 { http.get(url) }

trait Close

shared trait Close

The destructor of an object: what releases the resource behind it - a descriptor, a socket, a lock - once nothing holds the object any more.

Only a shared type implements it, because a value is copied on assignment and two copies would close one resource twice. No program calls close(): the last release of the object runs it, and a program that wants that moment early lets the scope end or binds the object with using name = value, whose name cannot leave its block. Inside close(), self may not be stored, returned or captured by a closure that outlives the call.

Examples

shared type Connection with Close {
  var isOpen: Bool = true

  fn send(message: String) {
    print message
  }

  var fn close() {
    isOpen = false
  }
}

fn greet() {
  using connection = Connection()
  connection.send "hello"
}

Open

No back end runs close() at the last release yet (docs/design/DESTRUCTORS.md, slice R1), so a program that needs a resource released today has no way to ask for it.

fn close

var fn close()

Releases the resource. Runs exactly once, when the last reference to the object goes away; it returns nothing, cannot fail and never waits, and a type whose graceful end can do either offers end() beside it.