Skip to content

[ffigen] Generate a non-throwing fromValueOrNull on Dart enums #3712

Open

Description

@jakobkordez

Problem

For each C enum, ffigen generates a Dart enum with a fromValue constructor that throws on any value it doesn't recognise:

static ATEntryPoint fromValue(int value) => switch (value) {
  0 => AutotestMenu,
  1 => NoSearch,
  // ...
  _ => throw ArgumentError('Unknown value for ATEntryPoint: $value'),
};

That's the right default when the native side only ever produces valid members. But many enum values come from outside the current build, for example:

  • records saved by a different version of the native library, with ids the current enum doesn't name
  • values read from files, labels or the network and cast to the enum without being checked
  • enums that gain new members over time, where older bindings should handle the new ids gracefully

In these cases an unknown value is expected, not a bug. The caller wants to check for it, keep the raw int, and carry on, not catch an ArgumentError.

Proposal

Generate a second static method next to fromValue that returns null instead of throwing:

static ATEntryPoint? fromValueOrNull(int value) => switch (value) {
  0 => AutotestMenu,
  1 => NoSearch,
  // ...
  _ => null,
};

fromValue could then just call it:

static ATEntryPoint fromValue(int value) =>
    fromValueOrNull(value) ??
    (throw ArgumentError('Unknown value for ATEntryPoint: $value'));

That keeps the generated output about the same size, since the switch appears only once.

Considerations

  • Naming: fromValueOrNull follows int.tryParse / firstOrNull style; tryFromValue would work too.
  • Opt-in vs. default: the method is small and has no effect unless called, so generating it always seems reasonable. If output size is a concern, it could sit behind an option.
  • Enums with duplicate values: these should behave the same as fromValue does today (it returns the canonical member).
  • Compatibility: the change only adds a method; existing fromValue behaviour stays the same.

Activity

  1. removed
    needs-triageNeeds triage from the team. Remove this label once triaged.
    on Sep 30, 2026
  2. liamappelbe commented on Sep 30, 2026

    @liamappelbe
    Contributor

    Sounds good. I don't think it needs to be opt-in. It can be always enabled.

  3. vikramsingh920 commented on Oct 4, 2026

    @vikramsingh920
    Contributor

    hii @jakobkordez and @liamappelbe
    if it is still available, I'd like to work on this.

  4. jakobkordez commented on Oct 5, 2026

    @jakobkordez
    ContributorAuthor

    Sorry, I had it already completed but not committed and opened yet.

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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions