Developer Guide

This guide goes deeper than Getting Started. Each section covers one type in full: design rationale, every combinator, composition with other types, and pitfalls to avoid.

New to dmx-fun? Start with the Introduction for a mental model of the library and a first taste of composition before diving into individual types.

Which type should I use?

Does the value simply may or may not exist? Option<T>
Can an operation fail with a typed error domain? Result<V, E>
Does it wrap legacy code that throws? Try<V>
Do you need to collect all validation errors? Validated<E, A>
Branching value with no success/failure semantics? Either<L, R>
Expensive computation to defer and cache? Lazy<T>

Type overview

Option<T> Nullability

A value that may or may not be present. The null-safe alternative.

Use when You have an optional field or a lookup that may yield no result.
Avoid when The absence carries meaning beyond "not found" — use Result instead.
Result<V, E> Error handling

Either a success value or a typed error. Models domain failures explicitly.

Use when An operation can fail and the caller needs to handle the error type.
Avoid when The error is always an exception message string — Try is simpler.
Try<V> Exception handling

Wraps a computation that may throw. Turns exceptions into values.

Use when You are calling legacy or third-party code that throws checked/runtime exceptions.
Avoid when You own the error type and want callers to branch on it — use Result.
Validated<E, A> Validation

Like Result but accumulates multiple errors instead of failing fast.

Use when You want to collect all validation errors at once (e.g. a form submission).
Avoid when You only care about the first failure — Result short-circuits and is simpler.
Either<L, R> Disjoint union

A neutral disjoint union with no success/failure semantics.

Use when You need a branching value where neither side is inherently an error.
Avoid when One side clearly represents failure — use Result for that semantic clarity.
Lazy<T> Deferred computation

A value computed at most once, on first access. Thread-safe memoization.

Use when You have an expensive computation you want to defer and cache.
Avoid when The value is cheap to produce — the overhead of wrapping it is not worth it.
Tuple2/3/4 Product types

Typed heterogeneous tuples. Named fields without a dedicated class.

Use when You need to return 2–4 values from a method without a dedicated record.
Avoid when The tuple has stable semantics — model it as a proper record instead.
NonEmptyList<T> Collections

A list guaranteed to have at least one element at compile time.

Use when An API contract requires at least one element and you want to enforce it in the type.
Avoid when Emptiness is a valid state — use a regular List.
NonEmptyMap<K, V> Collections

A map guaranteed to have at least one entry at compile time. Insertion order preserved.

Use when A registry, configuration, or lookup table that must always contain at least one entry.
Avoid when Emptiness is a valid state — use a regular Map.
NonEmptySet<T> Collections

A set guaranteed to have at least one element at compile time. No duplicates, insertion order preserved.

Use when Set semantics (no duplicates) with the additional guarantee of non-emptiness, e.g. user roles or product tags.
Avoid when Emptiness is a valid state — use a regular Set.
Guard<T> Validation

A composable, named predicate that produces a Validated result — the reusable building block for validation pipelines.

Use when You have repeated if/invalidNel validation patterns that should be defined once and composed declaratively.
Avoid when A single ad-hoc check is simpler — Guard shines when rules are reused or composed.
Resource<T> Resource management

A composable managed resource: acquire, use, and release with a guaranteed cleanup guarantee.

Use when You need to bracket an operation around a resource (file, connection, lock) and want to compose multiple resources safely.
Avoid when A simple try-with-resources block suffices and no composition is needed.
Accumulator<E, A> Tracing

A value paired with a side-channel accumulation (log, metrics, audit trail). The functional alternative to mutable shared state for cross-cutting concerns.

Use when You need to thread log entries, counters, or audit events through a pure computation chain without shared mutable state.
Avoid when A step can fail — use Result for error handling, or Validated to accumulate validation errors.
Checked interfaces Interop

Checked variants of Function, Supplier, Consumer, Runnable, plus TriFunction/QuadFunction.

Use when You need to pass lambdas that throw checked exceptions to higher-order functions.
Avoid when The lambda does not throw — use the standard java.util.function types.

Cross-type composition

The types interoperate through conversion methods. The Combining Types page covers the full conversion matrix and composition patterns such as railway-oriented pipelines and parallel validation.

Modules

Optional modules extend the library with integrations for popular frameworks and libraries. Each module is an independent dependency — add only what you need.

Contributing & Maintainer

Documentation for working on the library itself: local setup, CI pipelines, release process, and conventions for adding new modules.