# argumentative

`software.visionary:argumentative:2026.10.13` · https://codeberg.org/Kompuwiz/argumentative

Visionary Software Solutions Argumentative: typed command-line argument parsing and marshalling

A command-line parser and marshaller that converts <code>String[]</code> into application-defined Java types, with generated usage text and no runtime dependencies beyond the JDK.

## Rationale

**Why.** Each value is built by a converter the program supplies, so the compiler checks construction and nothing is created by reflection. The parser needs only the JDK, so build tools and other low-level programs can use it without adding dependencies.

**Problem.** Parsing <code>String[]</code> by hand repeats each option's name in the parsing loop, the usage text and the error messages, and scatters value conversion through the program.

**Solution.** Register each option once, with its converter. Parsing, usage text and unknown-option errors all come from that registration, and the program receives typed values.

## Key Concepts

### Typed arguments

**Role.** An <code>Argument&lt;T&gt;</code> exposes its value through <code>value()</code> and <code>Supplier.get()</code>. Implement <code>Flag</code> for a boolean switch, or an <code>Option&lt;T&gt;</code> subtype for an option that takes a value: <code>Required&lt;T&gt;</code> declares exactly one occurrence, <code>Additional&lt;T&gt;</code> at most one, and <code>OneOf&lt;T&gt;</code> exactly one alternative. Records can implement these interfaces directly; a sealed interface groups the alternatives of a <code>OneOf</code>.

### Registration and parsing

**Role.** Subclass <code>Arguments</code> and register accepted arguments through <code>Products</code>: <code>flag(instance)</code> for a flag, <code>option(Type.class, converter)</code> for an option with a value. Supplied converters control construction and validation. Registrations compose, so related commands can share options. Construction parses the input; iteration returns typed arguments in input order. <code>accepts(Type.class)</code> checks registration, and <code>usage()</code> formats required, optional and mutually exclusive options.

### Path lists

**Role.** <code>ArgFile</code> represents an optional list of paths. Its <code>listed(filename)</code> helper reads one path per line, ignoring surrounding whitespace, blank lines and <code>#</code> comment lines. An unreadable file causes <code>IllegalArgumentException</code>.

## How It Works

**Guarantees.** Unknown options and missing value tokens throw <code>IllegalArgumentException</code> during construction; conversion errors propagate from the converter. Parsing preserves every supplied occurrence, including duplicates. Enforcing the declared occurrence constraints is the caller's responsibility. Every parser recognizes <code>--help</code>, <code>-h</code> and a leading <code>help</code>; the caller handles displaying help.

**Thread safety.** The parsed argument list is immutable. Sharing it safely also requires thread-safe argument values and subclass state.

## Lane

**Purpose.** Parsing command-line options into typed values for a Java program.

**When to avoid.** Command lines built on subcommands or positional arguments, such as <code>git commit -m &lt;message&gt;</code>.

## Usage

Parse a path and a flag

```java
import java.nio.file.Path;
import software.visionary.argumentative.Arguments;
import software.visionary.argumentative.Flag;
import software.visionary.argumentative.option.Required;

record Root(Path value) implements Required<Path> { }
record Verbose() implements Flag { }

final class Rooted extends Arguments {
    Rooted(String... argv) {
        super(argv, options -> options
                .option(Root.class, text -> new Root(Path.of(text)))
                .flag(new Verbose()));
    }
}

var parsed = new Rooted("--root", "/src", "--verbose");
System.out.println(parsed.usage());
parsed.forEach(argument -> System.out.println(argument.value()));

```

Output

```text
--root <root> [--verbose]
/src
true

```

## Dependencies

- `software.visionary:junit-closure:2026.09.17` at Testing

## Caveats

- Option names are the class's simple name in lowercase: <code>Root</code> becomes <code>--root</code> and <code>-r</code>. The first registration wins a short-name collision; <code>-h</code> is reserved for help.
- Values occupy the next argv element, even if it starts with <code>-</code>. Positional arguments, <code>--name=value</code>, combined short flags and the <code>--</code> terminator are unsupported.

