Skip to content

Add generators for OptionalInt, OptionalLong and OptionalDouble #27

Closed

Description

@blemale

Summary

Generators.optional(Generator<T>) covers java.util.Optional<T>, but there's no equivalent for the primitive specializations OptionalInt, OptionalLong and OptionalDouble. I'd like to propose adding them, and I'm happy to send the PR if you're open to it.

Motivation

Some APIs use the primitive optionals in their signatures, either because they're in the JDK (IntStream.max(), LongStream.findFirst(), DoubleStream.average(), …) or because they want to avoid boxing. To test them with Hegel today, you have to write the mapping by hand every time:

Generator<OptionalLong> g = oneOf(
        just(OptionalLong.empty()),
        longs().min(0).max(100).map(OptionalLong::of));

This works, but it's boilerplate that optional(...) already handles for Optional<T>.

Also, forType / record derivation supports Optional<T> components but fails on an OptionalLong component with No default generator for java.util.OptionalLong. So a record like this can't be derived without an override:

record Stats(long count, OptionalLong max, OptionalDouble mean) {}

Proposed API

In shared/src/main/java/dev/hegel/Generators.java, next to optional:

public static Generator<OptionalInt> optionalInts(Generator<Integer> generator) {
    return oneOf(just(OptionalInt.empty()), generator.map(OptionalInt::of));
}

public static Generator<OptionalLong> optionalLongs(Generator<Long> generator) {
    return oneOf(just(OptionalLong.empty()), generator.map(OptionalLong::of));
}

public static Generator<OptionalDouble> optionalDoubles(Generator<Double> generator) {
    return oneOf(just(OptionalDouble.empty()), generator.map(OptionalDouble::of));
}

Alternative: overload optional

Another option is to overload optional on the concrete generator types, so there's no new name to learn:

public static Generator<OptionalInt> optional(IntegerGenerator generator) {
    return oneOf(just(OptionalInt.empty()), generator.map(OptionalInt::of));
}

public static Generator<OptionalLong> optional(LongGenerator generator) {
    return oneOf(just(OptionalLong.empty()), generator.map(OptionalLong::of));
}

public static Generator<OptionalDouble> optional(DoubleGenerator generator) {
    return oneOf(just(OptionalDouble.empty()), generator.map(OptionalDouble::of));
}

Derivation support

In shared/src/main/java/dev/hegel/generators/Derive.java, add the three classes to scalar(...) so that forType and records support them:

if (cls == java.util.OptionalInt.class) {
    return Generators.optionalInts(Generators.integers());
}
// same for OptionalLong / OptionalDouble

Does this sound reasonable? If so, I'll go ahead with a PR. Any feedback on naming or scope is welcome.

Activity

  1. esauro commented on Oct 8, 2026

    @esauro
    Contributor

    This proposal looks very reasonable to me. I'm looking forward to see your PR.

  2. added a commit that references this issue on Oct 12, 2026
    a681b67
  3. blemale commented on Oct 12, 2026

    @blemale
    ContributorAuthor

    Here is the PR: #33

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions