Skip to content
HARA
>_

Hara runtime libraries

Hara keeps its automatically referred core small. The runtime generates the library namespaces; they are not backed by .hal source files and do not expose their JVM implementation.

Every namespace receives these aliases by default:

Alias Generated namespace Xtalk family
str/ std.lib.string x:str-*
promise/ std.lib.promise x:promise-*, x:with-delay
bytes/ std.lib.bytes byte operations
socket/ std.lib.socket x:socket-*
file/ std.lib.file x:file-*
block/ std.lib.block source-preserving Hara blocks
zip/ std.lib.zip persistent tree zipper navigation

(ns app) and (ns app (:config {:intrinsics :all})) are equivalent. Aliases can be excluded or renamed through the singular :alias option:

(ns app
  (:config
    {:intrinsics
     {:exclude [bytes]
      :alias {string text
              promise async}}}))

Exclusion only removes the qualified alias. It does not remove core constructors such as bytes. Generated namespaces also work with ordinary namespace clauses:

(ns app
  (:config {:intrinsics {:exclude [string]}})
  (:require [std.lib.string :as text :refer [trim]]))

Standalone :intrinsics and :builtins clauses are not valid; foundation configuration only lives inside the single optional :config map.

The core constructors are str, promise, bytes, array, and object. Core also provides signed 32-bit bit-and, bit-or, bit-xor, bit-not, bit-shift-left, and bit-shift-right.

array and object create mutable marker values distinct from persistent [] and {}. Dot calls are accepted only on those marker values:

(. (array 1 2 3) (filter (fn [x] (> x 1))))
(. (object "name" "Hara") (get "name"))

Array methods are get, set, push-first, push-last, pop-first, pop-last, insert, remove, slice, clone, map, filter, fold-left, and fold-right. Object methods are has?, get, set, delete, clone, assign, keys, vals, and pairs. Object keys are strings.

Promises are backed by the runtime's native promise mechanism. On the JVM that is CompletableFuture. promise/run, promise/new, promise/all, promise/then, promise/catch, promise/finally, promise/native?, and promise/delay follow the xt.lang.spec-promise settlement and adoption model.

Bytes expose unsigned values from 0 through 255 through bytes/get; bytes/u8 and bytes/s8 explicitly convert representations. The ordinary bytes/get library operation is unsigned, while protocol INth/nth preserves the signed byte value. String encoding and decoding are UTF-8.

File and socket namespaces are always present and aliased. Availability does not grant authority. Unsupported or denied operations fail when invoked. JVM embeddings grant authority with Graal IOAccess; the CLI grants it explicitly with --allow-file and --allow-net. file/resolve resolves a child path beneath a supplied root and returns a normalized path string. File reads and writes use bytes and return promises. Socket v1 follows the callback contract: connect accepts host, port, a reserved options value, and an (fn [error connection] ...) callback; the current implementation does not interpret options. send accepts bytes and returns the byte count; close is direct. Receive/framing and HTTP are outside this slice.

Additional provider-backed namespaces are available through ordinary require and are not automatically aliased:

Namespace Purpose
std.lib.handle releases opaque HTA extension handles
std.lib.context context registries, runtime spaces, lifecycles, and pointers
std.lib.task task definitions, invocation, selection, and bulk processing
std.foundation.coroutine Lua-style coroutines: create, resume, yield, status, close, await
code.test facts, fixtures, matchers, and structured test execution

These providers are installed lazily under their canonical public namespace. Their implementation classes and helper namespaces are not guest-visible API. Requiring a provider does not grant file, network, process, reflection, classpath, or compilation authority.

std.foundation.coroutine provides Lua-style coroutines on the Truffle and Rust runtimes. create wraps a function without starting it; resume starts or continues a coroutine and returns the yielded or final value; yield suspends the current coroutine from any call depth and returns the next resume's arguments; status reports :suspended, :running, or :dead. With multiple values, yield and resume arguments pack into vectors (single values pass through as-is). Errors inside a body rethrow at the resume site and leave the coroutine :dead. close unwinds a suspended coroutine, running its finally clauses. await blocks the coroutine until a promise settles. Plain (yield p) hands a promise object out to the resumer without awaiting it; use (yield (await p)) to suspend until the promise settles and then yield its value. A single coroutine is not safe for concurrent resume/close calls from multiple threads; resume is synchronous and single-resumer by design. Var bindings established around a resume do not propagate into the coroutine body.

std.resp.client is a separate, explicitly required blocking RESP2 client. It exposes connect, call, write, read, pipeline, open?, and close; connections require network capability. Bulk strings decode as UTF-8 strings by default and can be preserved as bytes with {:decode-bulk :bytes}.