Brass cheat sheet

Use this sheet to look up Brass syntax through short examples from a dinosaur park. Each section links to the rule in the specification, which decides what is valid.

The rejection notes describe language rules, including checks still to be implemented. Today's brass tool checks program structure, runs examples and answers questions about the code. Proving function contracts requires the full checker.

The smallest program

A module declares and implements a greeting. The system file makes it callable by the host.

# hello/greet.brass
module hello.greet

interface
  fn greet(name: Text) -> Text
    example greet("Ada") == "Hello, Ada"

body
  fn greet(name) = "Hello, " ++ name
# system.brass
system hello
  grants hello.greet.greet: none
  limit  cpu_ms 1000
  limit  memory_bytes 16777216
  limit  transcript_bytes 1048576, drop oldest

A program is its modules plus one system.brass. The host calls an entry point by its full name, hello.greet.greet; there is no main. Only a function with a grants line can be called from outside. There is no print: output goes through an access (Authority).

Comments

# park/ids.brass — declaration excerpt
# a comment runs from # to the end of the line
type PaddockId = Int where it in 1 to 40   # at the end of a line, too

A comment directly above a declaration is shown by brass info.

Modules and imports

# park/doors.brass — layout
module park.doors
import park.enclosures as enclosures

interface
  …
private
  …
body
  …

Spec §4

Names

What Case Example
types, constructors, states Uppercase Paddock, Species.Rex
modules, functions, parameters, fields, aliases lowercase park.doors, secure, p.id

Constructors are qualified by their type: Species.Rex, FailureCode.NotFound. Ok, Err, Done and None stay bare. A keyword is never a name.

Built-in types

Type Meaning
Int signed 64-bit integer; also Int8 Int16 Int32 Int64
Float 64-bit IEEE float
Bool true or false
Text text; length counts characters
Bytes a byte sequence
Array<T> ordered; literals [], [a, b]
Set<T> for membership and bounds; literal {a, b}; not iterable
Maybe<T> a T or None
Outcome<T> Ok(T) or Err(FailureCode, Text)
Done the one value of a call with nothing to return: Outcome<Done>

No Map, no function values, no null. Spec §2

Bindings and constants

Use const for a value known to the checker and let for a local binding.

# park/enclosures.brass — excerpts
interface
  const max_heads: Int = 12

body
  fn total(…) =
    let count: Int = 0        # every let names its type
    count = count + 1         # rebinding: same type, local lets only
    count

Operators

Kind Operators
arithmetic + - * / %, -x
powers a ^ b, constants only
join text or arrays ++
compare == != < <= > >=
logic and or not
membership, type test in, is
pass up a failure ?

Full precedence table: spec §2.2

Text

# park/signs.brass — body excerpt; needs `import std.text as text`
fn sign(p) =
  let label: Text = "Paddock " ++ text.of(p.id)
  if label.length <= 20 then label else "Paddock"

text.of turns an Int into its decimal text. Using std needs requires std = brass.std v0.2 in system.brass.

Records and sums

# park/enclosures.brass — excerpts
type Species = Goat | Raptor | Rex                     # a sum: bare names, no payloads
type Paddock = { id: PaddockId, species: Species, status: Enclosure }

let p: Paddock = { id: 2, species: Species.Rex, status: Enclosure.Secured }
let q: Paddock = p with { species: Species.Raptor }   # a copy; p is unchanged

If and else

# park/enclosures.brass — body excerpt
fn ration(species) =
  if species in {Species.Goat} then 2000
  else if species in {Species.Raptor} then 12000
  else 50000

Loops

# park/doors.brass — body excerpt
for attempt in 1 to 3                 # both ends included: 1, 2, 3
  last = doors.close(operator, p.id)
  if last is Ok then break

for p in paddocks                     # paddocks: Array<Paddock> where it.length in 0 to 40
  …
# park/enclosures.brass — body excerpt
any p in ps where p is OpenPaddock and p.species in {Species.Rex}
all p in ps where p.status in {Enclosure.Secured}

Spec §3

Functions

# park/enclosures.brass
module park.enclosures

interface
  fn ration(species: Species) -> Grams    # declaration: types and promises

body
  fn ration(species) =                    # body: parameter names only
    if species in {Species.Goat} then 2000
    else 50000

Promises: before, after, example

A function can state a general condition, or give one concrete call and the answer it must give.

# park/enclosures.brass — declaration excerpt
fn secure(p: OpenPaddock) -> SecuredPaddock
  after result.id == p.id

fn ration(species: Species) -> Grams
  example ration(Species.Goat) == 2000
Line Who makes it true Checked
before the caller proven at check time
after the body, on success proven at check time
example the body run by brass check

Spec §6

Types with conditions: where and is

# park/enclosures.brass — declaration excerpts
type PaddockId   = Int where it in 1 to 40
type OpenPaddock = Paddock where it.status in {Enclosure.Open}
type Pen         = Array<Paddock> where it.length in 0 to 40
# park/doors.brass — body excerpt
if p is enclosures.OpenPaddock then
  Ok(enclosures.secure(p))             # p counts as an OpenPaddock here
else Err(FailureCode.Conflict, "paddock is not open")

Spec §7

Errors: Outcome and ?

# park/doors.brass — body excerpt
fn lockdown_as(doors, operator, paddock) =
  let p: enclosures.Paddock = doors.enclosure(paddock)?   # the Ok value, or return the Err
  if p is enclosures.OpenPaddock then
    doors.close(operator, p.id)?
    Ok(enclosures.secure(p))
  else Err(FailureCode.Conflict, "paddock is not open")

Spec §5, §10.4

Absence: Maybe

# park/enclosures.brass — excerpt
fn signers(first: BadgeId, second: Maybe<BadgeId>) -> Int
fn signers(first, second) =
  if second != None and second != first then 2 else 1   # right of and: a plain BadgeId

State machines

# park/enclosures.brass — excerpts
machine Enclosure
  states  Secured, Open, Breached
  initial Secured
  Secured enters Open
  Open    enters Secured | Breached

fn secure(p) = p with { status enters Enclosure.Secured }
# park/enclosures.brass — a variant of Paddock
type Paddock = { id:          PaddockId,
                 status:      Enclosure,
                 breached_at: Int when it.status in {Enclosure.Breached} }

Spec §9

Authority: access, allow, grants

# park/doors.brass — declaration excerpt
access Doors { paddocks: Set<enclosures.PaddockId>, deadline_ms: Int }
  allow close(operator: enclosures.DoorOperator, paddock: enclosures.PaddockId) -> Outcome<Done>
    before paddock in paddocks

fn lockdown_as(doors: Doors, operator: enclosures.DoorOperator, paddock: enclosures.PaddockId) -> Outcome<enclosures.SecuredPaddock>
# system.brass — grant excerpt
grants park.doors.lockdown_request: doors = Doors { paddocks: {1, 2, 3}, deadline_ms: 30000 }

Spec §8

The system file

# system.brass
system park
  requires std = brass.std v0.2
  grants   park.doors.lockdown_request: doors = Doors { paddocks: {1, 2, 3}, deadline_ms: 30000 }
  limit    cpu_ms 5000
  limit    memory_bytes 268435456
  limit    transcript_bytes 67108864, drop oldest
  limit    impact_modules 4
Line Meaning
requires an exact release of an outside dependency
grants an entry point and the access it gets; : none if it needs none
limit cpu_ms, memory_bytes, transcript_bytes required; the first two abort the task when exceeded
limit impact_modules optional review notice when a change reaches too many modules

brass writes a lock file beside the system file. Nobody edits it by hand.

Holes

# park/doors.brass — body excerpt
doors.close(@@operator, p.id)?

@@name marks an expression not written yet. The program is rejected until it's filled; brass check names the type that fits.

What brass reports

Command What it does
brass check checks the whole program and runs every example
brass info <name> one declaration: its promises, their labels, who uses it
brass show <module> … the declarations of the modules named, exactly as written
brass apply applies a patch, checking it before anything is written

Every promise is labeled:

Not in Brass

Instead of Brass has
classes and inheritance records and projects to
exceptions Outcome<T> and ?
null Maybe<T>
return the last line
while, recursion bounded for
match if with is and in
mutation with
casts x is T
global services access parameters
pub / private per item interface and private sections
"a" + "b" "a" ++ "b"
overloading, macros one form for each thing

Spec §15

Coming from Python

Coming from Rust