Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Source files and declarations

Spaces delimit indented suites. Tabs are rejected, and indentation must return to an existing level. Blank lines and comment-only lines do not affect indentation. Parentheses permit multiline expressions. Comments start with #.

Identifiers contain ASCII letters, digits, and underscores and cannot start with a digit. Keywords and names beginning __plenty_ are reserved. Diagnostics use one-based line and column positions.

Strings accept single, double, or triple quotes; triple quotes permit physical newlines. The first standalone string in an indented function body is its documentation. Use return "text" when that first string should be the returned value. A b prefix makes a byte literal, b"...", which holds ASCII characters and \xHH escapes. Strings accept the escapes \0, \n, \r, \t, \\, \', \", and \u{H...} for a scalar by code point. Integer literals are decimal, hexadecimal (0xFF), octal (0o17), or binary (0b1010), with optional _ digit separators and width suffixes.

Module scope contains functions, classes, enums, protocols, type aliases, constants, static assertions, imports, and target conditionals. Executable statements and mutable bindings belong inside functions; there are no global variables. Named functions belong at module scope; classes and enums can declare methods, and protocols declare method requirements. Anonymous functions can appear in function bodies; see functions.

A line holding only @name annotates the declaration below it. The set of annotations is closed and compiler-known: @copy and @newtype on classes, and @redacted on classes and enums. See annotations.

Names follow lexical scope and prelude rules. Modules use explicit imports, with visibility controlled by pub. An application has a main entrypoint.

Keywords

A keyword cannot name a binding, parameter, field, function, type, or module. These keywords have a meaning in Plenty:

and, as, break, case, class, const, continue, def, dimension, elif, else, enum, export, extern, False, for, from, if, import, in, match, mut, not, opaque, or, pass, protocol, pub, return, True, type, while, with, yield

These are reserved but have no meaning, so a Python or Rust habit is rejected instead of becoming a name:

async, await, lambda, None, struct, trait, try

None, try, and lambda have diagnostics that name the replacement: Nothing, a Result, and an anonymous function. self and is are not keywords. except, finally, and raise are not reserved either, but a statement that begins like Python exception handling is rejected.