Liking cljdoc? Tell your friends :D

souther.behavior

Implementing a Souther injected behavior from Clojure.

A required/injected behavior is generated as an abstract base class (it carries the protected factories for its declared output cases, aimed at a Java subclass). Clojure implements it with proxy. Because a proxy cannot reach those protected factories, results are built through the public decoder() instead -- see souther.decode/construct. defbehavior is the small amount of sugar over proxy that names the implementation and mirrors the generated apply signature. as-fn turns a bound/unary behavior into a plain Clojure fn, called (f input) rather than (.apply behavior input).

Implementing a Souther injected behavior from Clojure.

A `required`/injected behavior is generated as an abstract base class (it carries the protected
factories for its declared output cases, aimed at a Java subclass). Clojure implements it with
`proxy`. Because a proxy cannot reach those protected factories, results are built through the
public `decoder()` instead -- see `souther.decode/construct`. `defbehavior` is the small amount
of sugar over `proxy` that names the implementation and mirrors the generated `apply` signature.
`as-fn` turns a bound/unary behavior into a plain Clojure fn, called `(f input)` rather than
`(.apply behavior input)`.
raw docstring

souther.build

Build-time helper: run the Souther annotation processor to generate the classes for a .sou module, without Maven. This drives javac through the JDK compiler API (javax.tools), so the only thing the caller must provide is the souther-compiler jar on the invoking classpath -- typically via a deps.edn alias -- where the processor is discovered by ServiceLoader.

Unlike the rest of souther-clj this namespace is not used at runtime; it depends on nothing beyond the JDK (it never imports the processor class, only names it to javac).

Build-time helper: run the Souther annotation processor to generate the classes for a `.sou`
module, without Maven. This drives javac through the JDK compiler API (`javax.tools`), so the
only thing the caller must provide is the `souther-compiler` jar on the invoking classpath --
typically via a deps.edn alias -- where the processor is discovered by ServiceLoader.

Unlike the rest of souther-clj this namespace is not used at runtime; it depends on nothing
beyond the JDK (it never imports the processor class, only names it to javac).
raw docstring

souther.decode

Decoding and constructing Souther-generated domain values from Clojure data.

Souther generates, for every data type, a public decoder() (a Raoh Decoder) that runs the type's invariants. Because data constructors are non-public, this decoder is the construction path for a boundary that does not extends the generated code -- a Clojure proxy, or any non-JVM-subclass consumer. This namespace wraps that path in Clojure terms: keyword-keyed maps are accepted (keys are stringified to the field names the decoder expects), and a decode failure comes back as Clojure data (Raoh Issues) rather than a Java Result to pick apart.

Decoding and constructing Souther-generated domain values from Clojure data.

Souther generates, for every data type, a public `decoder()` (a Raoh `Decoder`) that runs the
type's invariants. Because data constructors are non-public, this decoder is the construction
path for a boundary that does not `extends` the generated code -- a Clojure `proxy`, or any
non-JVM-subclass consumer. This namespace wraps that path in Clojure terms: keyword-keyed maps
are accepted (keys are stringified to the field names the decoder expects), and a decode failure
comes back as Clojure data (Raoh Issues) rather than a Java Result to pick apart.
raw docstring

souther.encode

Encoding Souther-generated values back to Clojure data -- the inverse of souther.decode.

Every generated type has a public encoder() that yields its external representation: a newtype encodes to its bare underlying value, a record/sum to a map (with nested newtypes already unwrapped). That is exactly the unwrapping a Clojure boundary wants, so encode runs the encoder and hands back Clojure data -- no chains of .value / field accessors.

Encoding Souther-generated values back to Clojure data -- the inverse of `souther.decode`.

Every generated type has a public `encoder()` that yields its external representation: a newtype
encodes to its bare underlying value, a record/sum to a map (with nested newtypes already
unwrapped). That is exactly the unwrapping a Clojure boundary wants, so `encode` runs the
encoder and hands back Clojure data -- no chains of `.value` / field accessors.
raw docstring

souther.match

Exhaustive folding of a Souther sealed output union at the Clojure boundary.

Souther's match is total: every case of a union is handled. That guarantee is a compile-time property of the generated code and is lost the moment a value crosses into Clojure, where a forgotten case just silently falls through. case-of restores it: the generated union interface is sealed, so its permitted subclasses are known by reflection, and case-of checks -- at macro expansion -- that the handler map covers exactly those cases before emitting the dispatch.

Exhaustive folding of a Souther sealed output union at the Clojure boundary.

Souther's `match` is total: every case of a union is handled. That guarantee is a compile-time
property of the generated code and is lost the moment a value crosses into Clojure, where a
forgotten case just silently falls through. `case-of` restores it: the generated union interface
is sealed, so its permitted subclasses are known by reflection, and `case-of` checks -- at macro
expansion -- that the handler map covers exactly those cases before emitting the dispatch.
raw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close