Skip to content

feat: honor the omitzero struct-tag option#392

Open
gdamore wants to merge 1 commit into
vmihailenco:v5from
gdamore:feat/omitzero
Open

feat: honor the omitzero struct-tag option#392
gdamore wants to merge 1 commit into
vmihailenco:v5from
gdamore:feat/omitzero

Conversation

@gdamore

@gdamore gdamore commented Jun 24, 2026

Copy link
Copy Markdown

Summary

encoding/json gained the omitzero field option in Go 1.24: a field is omitted when it holds the zero value for its type, as determined by an IsZero() bool method if present, otherwise by reflect.Value.IsZero(). msgpack's tag parser already recognizes the option (tag.HasOption("omitzero")), but it was silently ignored, so a zero-valued field tagged ,omitzero was always encoded.

This honors omitzero in field.Omit, independently of omitempty.

Details

  • A new isZeroValue helper mirrors encoding/json's omitzero semantics:
    • a type's own IsZero() takes precedence;
    • a nil pointer/interface is treated as zero up front, so a typed-nil whose type carries an IsZero method (e.g. (*time.Time)(nil)) is not dereferenced — the same guard encoding/json uses;
    • otherwise reflect.Value.IsZero() decides.
  • Unlike omitempty's isEmptyValue, it does not treat a non-nil empty slice, map, or string as omittable — omitempty and omitzero are intentionally distinct, as in encoding/json.
  • Works with a custom struct tag (e.g. SetCustomStructTag("json")) too, since the option is parsed generically.

Test

TestOmitZero covers int/string/bool zero values, a type with a value-receiver IsZero, and a nil *time.Time (exercising the nil-pointer guard). It fails on v5 without this change and passes with it.

Notes

Related to #390, which discusses aligning omit semantics with encoding/json and notes omitzero as the path Go took. This PR adds the omitzero option specifically; it does not change existing omitempty behavior.

encoding/json gained the `omitzero` field option in Go 1.24: a field is
omitted when it holds the zero value for its type, as determined by an
`IsZero() bool` method if present, otherwise by reflect.Value.IsZero().
The tag parser already recognizes the option, but it was silently
ignored, so a zero-valued field tagged `,omitzero` was always encoded.

Honor it in field.Omit, independently of `omitempty`. A new isZeroValue
helper mirrors encoding/json's semantics: a type's own IsZero takes
precedence, a nil pointer/interface is treated as zero up front (so a
typed-nil whose type carries an IsZero method is not dereferenced), and
otherwise reflect.Value.IsZero() decides. Unlike omitempty's
isEmptyValue, it does not treat a non-nil empty slice, map, or string as
omittable.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant