go-composites

Small, hand-written composites for Go — a Result/Option value type, a null-object Error, and array and string types that thread failures through one shared Result channel.

pure Go · cgo-free null-object pattern Result / Option value type 100% coverage · 6-arch CI nonnil / respondto analyzers BSD-3-Clause
Get started GitHub

go-composites is an experiment in Composition-Oriented Programming for Go: composites are assembled by composition and interfaces rather than inheritance. Every package exposes an Interface with a New constructor, and operations return a Result rather than Go's idiomatic multiple-return error. The null-object pattern runs throughout — a fresh Result, Error or Null is a real, non-nil value — so callers branch on HasError() instead of nil checks.

The packages build on each other: result sits on null and error; array's methods all return a Result; and string.Split returns a Result wrapping an array of strings. Two static analyzers keep the invariants honest — nonnil fails the build on a bare-nil return and respondto on a reflective send to a missing method — and every library package is held to 100% statement coverage across a native + emulated six-architecture CI matrix.

Repositories

null core

Null.New() · null-object value

A null-object primitive used as the default payload across the org, so empty results carry a real value instead of a nil interface{}.

error core

Error.New(message) · Message() · IsNull() · src/null null-error

A small Error interface (Message, IsNull) with a null-object variant, so the absence of an error is itself a value rather than a nil check.

result core

Result.New(WithPayload / WithError) · Payload() · HasError() · Error()

The Result value type every other package returns: a payload plus an error, in the style of an Option/Result. Built on null and error, with a null-object default so a fresh Result is non-nil and error-free.

base core

the shared foundation every composite builds on

Common scaffolding the other composites embed and reuse, keeping the per-repo surface small.

boolean container

Boolean.New(b) · True() · False() · IsTrue() · IsFalse() · Equal · Inspect

A boxed boolean composite. Its structural IsTrue() is what array's combinators recognise as truthy, without array having to import boolean.

number container

Number.New(WithInt / WithFloat) · arithmetic → Result

A boxed numeric value over int and float. Arithmetic returns a Result, so division by zero is an error value rather than a panic.

bignumber container

BigNumber.FromInt64 · FromString → Result · Add/Sub/Mul/Div/Mod/Abs/Neg

An arbitrary-precision integer over math/big — Ruby's unbounded Integer. Same Result-based arithmetic as number (Div/Mod by zero are errors), so values never overflow or panic.

rational container

Rational.FromInts / FromString → Result · Numerator/Denominator · ToFloat · arithmetic

An exact rational over math/big.Rat — Ruby's Rational. Fractions stay exact (1/3 + 1/6 == 1/2, no float error); division by a zero rational is an error Result.

complex container

Complex.New(re, im) · FromReal · Real/Imaginary · Abs · Conjugate · arithmetic

A complex number a+bi — Ruby's Complex, over Go's complex128. Add/Sub/Mul/Div return a Result (÷ by 0+0i is an error, not NaN); Abs is the magnitude, Conjugate flips the sign of the imaginary part.

bigfloat container

BigFloat.FromFloat64 / FromString → Result · arithmetic · ToFloat64

An arbitrary-precision float over math/big.Float (256-bit). More precision than float64 where it matters; division by zero is an error Result. Rounds out the numeric tower next to bignumber and rational.

string container

String.New(WithGoString) · Set · ToGoString · Split · IsNull

A String value type over Go's string. Split returns a Result wrapping an array, threading the array, result and error primitives together.

buffer container

Buffer.New() / From(s) · Append · AppendRune · Reset · ToGoString · Len

A mutable text buffer (StringBuilder) over strings.Builder — the mutable counterpart to the immutable string value. Append/AppendRune/Reset mutate in place and chain. Zero dependencies.

array container

Array.New() · Each/Map/Filter/Reduce/Find/Any/All · Push/Pop/First/Last/Fetch

An interface{}-backed dynamic array whose methods all return a Result. Beyond stack access it carries functional combinators (Map, Filter, Reduce, Find, Any, All) that short-circuit on the first error Result.

dictionary container

Dictionary.New(WithPairs) · Get/Set → Result · IsNull

An interface-first key/value map. Get of a missing key returns a Result carrying an error, never a panic, matching the rest of the org's failure channel.

set container

Set.New(items…) · Add/Delete/Has · Union/Intersection/Difference · IsSubset

An unordered collection of unique items, backed by a map. Carries the usual set algebra (union/intersection/difference, subset, equality) plus Each/ToArray, with a Null-Object variant.

orderedset container

OrderedSet.New(items…) · same algebra as set · insertion-ordered Each/ToArray

A set that remembers the order items were first added (slice + map). Same algebra as set but with deterministic iteration — handy when order matters and for reproducible output.

sortedset container

SortedSet.New(less, items…) · sorted Each/ToArray · First/Last (min/max)

A set kept sorted by a comparator (sorted slice + map), TreeSet-like. Iteration is in comparator order and First/Last give the min/max in O(1). Set algebra preserves the order.

bag container

Bag.New(items…) · Add/Remove · Count · Sum/Union/Intersection/Difference

A multiset / counter — items with multiplicity. Count(item) gives occurrences; multiset algebra adds/maxes/mins/subtracts counts. Completes the collection family next to set, orderedset and sortedset.

range container

Range.New(begin, end, WithStep / Exclusive) → Result · Includes · Each · ToArray

A numeric integer interval — inclusive (..) or exclusive (...), with a non-zero step. New returns a Result (a zero step is an error, not a panic); elements are exposed as Numbers.

pair container

Pair.New(first, second) · First · Second · Equal · ToArray

A fixed two-element heterogeneous grouping — the natural key/value entry. Equal compares both slots; ToArray materialises a two-element Array. Null-Object variant included.

symbol container

Symbol.New(name) · interned · ToGoString · Equal · Inspect

An interned, immutable identifier in the Ruby :name spirit — New("x") and New("x") are the same instance (a mutex-guarded registry), so identity comparison is cheap and exact.

time container

Time.FromUnix · Parse → Result · Before/After/Add/Sub · In/Zone/UTC · Duration

A Time instant plus a Duration subpackage, over Go's stdlib time. Deterministic by design (no Now()); Parse returns a Result on bad input. IANA time zones via In/Zone/UTC (tzdata embedded for every arch). Time.Sub yields a Duration.

date container

Date.FromYMD / Parse · Year/Month/Day/Weekday · AddDays · DaysBetween · comparisons

A calendar date (year/month/day, no time) — Ruby's Date. FromYMD/Parse return a Result so an invalid date (Feb 30) is a value, not a panic; AddDays/DaysBetween do calendar arithmetic. Null-Object variant.

proc combinator

Proc.New(fn) · Call(args…) → Result · Then(next) railway

A first-class callable: wrap a Result-returning function and Call it, or chain with Then — feeding each payload to the next and short-circuiting on the first error. A callable value, where compose is a pipeline of steps.

enumerator combinator

New / Generate · Map · Filter · Take (lazy) · ToArray / Each / First / Reduce

A lazy sequence in the Ruby Enumerator::Lazy spirit. Map/Filter/Take are lazy — they wrap a producer and evaluate nothing until a terminal pulls items — so Take of a finite prefix terminates even an infinite Generate source. Terminals thread the shared Result channel.

compose combinator

Pipe(steps…) · Run(input, steps…) · Then · Map · Recover · Fail

Pipe composes Result-returning steps into one left-to-right pipeline that threads the payload forward and short-circuits on the first error; Run applies it to an input, with Recover/Fail for error handling — function composition over the shared Result channel.

composites meta

import "github.com/go-composites/composites" · type aliases + constructors

The meta-package: one import that re-exports the whole vocabulary (Array, Boolean, String, Number, Dictionary, Set, Range, Pair, Symbol, Time, Date, Proc, Enumerator, BigNumber, Rational, Complex, BigFloat, OrderedSet, SortedSet, Bag, Buffer, Result, Error, Null) as type aliases and constructor values — zero wrapping cost, full interoperability.

typed generic

Result[T] · Optional[T] · Slice[T] (Map/Filter/Reduce/Find/Any/All)

A generics parallel track: the same patterns with compile-time type safety, so a payload-type mismatch becomes a build error. Complementary to — not a replacement for — the reflective, dynamic composites.

nonnil tool

go vet analyzer · enforces the Null-Object invariant

A go vet-style analyzer that fails the build when an interface carrying IsNull() is returned, assigned, or stored as a bare nil. Runs in CI on every repo.

respondto tool

go vet analyzer · checks reflective dispatch targets

A go vet-style analyzer for reflective sends: it flags RespondTo / method-name calls whose target method does not exist, catching typo'd dynamic dispatch at build time.

Every package is pure Go and BSD-3-Clause, structured around an Interface + New constructor and the null-object pattern. A few names (such as object and is) remain empty placeholders for future primitives and are left off this list until they ship code.