Standard Library

The standard library is made of modules loaded with use(). For functions available without use(), see Built-in Functions.

A locator given to use() is resolved against your package first, then against the packages your manifest names, and finally against the shop’s standard set. That produces three tiers, and which tier a module is in decides whether you can just name it.

pitlib — core to the language

These are the modules the language expects to find — the counterpart to a C program’s standard library. Every shop provides them, every package reaches them by bare name, and their behaviour is the same everywhere.

pitlib is a name for that role, and this is one implementation of it. Like a libc, it can be swapped: a shop can supply its own pitlib as long as it offers the same modules, and code written against the language keeps working.

ModuleProvides
blobBinary data, addressed in bits
jsonJSON encoding and decoding
math/radiansTrigonometry, logarithms, roots — also math/degrees, math/cycles
randomRandom numbers
timeClock, calendar records, and duration constants
fitFixed-width integer and bit operations, at the target’s native integer width

The trigonometric modules are named by the angle unit they take, so use('math/radians'), use('math/degrees'), or use('math/cycles').

std — the shop’s standard surface

std is also reachable by bare name, but it belongs to the shop rather than to the language: a different shop may supply a different std. It currently provides the two input/output modules.

ModuleProvides
filePortable asynchronous filesystem
ioReading and writing byte channels

Both select a per-target implementation while presenting one shape — see Per-target modules below.

Reachable, but not standard

pitlib and std are the two tiers you can name bare. Everything else is an ordinary package you name in full or alias, and that is by far the larger set. Nothing on this page privileges those, and nothing forbids them either — being reachable and being a fallback are different questions, as Standard packages puts it.

A few are documented in this section because programs reach for them often, and they must not be mistaken for standard packages. They are shoplib’s cryptography — there is no crypto anywhere in pitlib or std, and no single module that gathers these four:

ModuleProvides
shoplib::cryptoBLAKE2b, authenticated encryption, X25519 agreement, Ed25519 sign/verify, secure random
shoplib::eddsaEd25519 key derivation from a seed
shoplib::sha1SHA-1, for protocols that name it
shoplib::sha256SHA-256, for protocols that name it

shoplib is the shop’s own machinery. It is on no fallback list, so there is no bare use('crypto') — you write use('shoplib::crypto') and say where it came from.

Per-target modules

Some modules exist in a different form on each target. use('file') gives you the same record everywhere, but the implementation underneath is chosen for the platform you are building for — a Darwin build binds one file provider, a Linux build another, a Playdate build another still.

The choice is made by the package manifest, which maps a logical module name to a per-target implementation:

{
  "modules": {
    "file": {
      "darwin": "internal/file_darwin",
      "linux": "internal/file_linux",
      "windows": "internal/file_windows"
    }
  }
}

Two things about that are worth knowing. There is no file.cm — the arms are the whole definition of the name, so there is no placeholder file to drift out of step with them. And std keeps its implementations under internal/, which is package-private, so nobody can reach past std::file to bind one platform’s implementation directly.

That second one is std’s choice, not a requirement. An arm value is any package-relative path; a package is free to publish its per-target implementations at its top level where other packages can name them, and some should. std hides them because std::file is meant to be the only door.

Every implementation returns the same shape, so your code does not change. If a target has no arm, the build says so and names the target rather than substituting something that will not work.

This is why a module can be genuinely unavailable on a target: a console build with no network stack has no arm for the socket provider, and a program that imports it fails to build for that target.

None of this is privileged. std::file is the worked example of the pattern, and a program that knows which machine it is for may claim $posix_file or $darwin_file itself and skip the portable layer.