Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[chore] Create RFC for Optional config types #12596

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

evan-bradley
Copy link
Contributor

@evan-bradley evan-bradley commented Mar 10, 2025

Description

This RFC will help us explore the use cases Optional types solve and move us toward a resolution for whether to adopt these in our config.

Related to #10266

Copy link

codecov bot commented Mar 10, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 92.09%. Comparing base (7d3e03e) to head (94e8a78).
Report is 11 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #12596      +/-   ##
==========================================
- Coverage   92.18%   92.09%   -0.09%     
==========================================
  Files         469      473       +4     
  Lines       25394    25590     +196     
==========================================
+ Hits        23409    23567     +158     
- Misses       1574     1612      +38     
  Partials      411      411              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@evan-bradley
Copy link
Contributor Author

@yurishkuro could you take a look at this? We're taking a closer look at whether we want this type for 1.0 and want to make sure if we add it that it will cover all config use cases and won't have any major downsides. I would appreciate your input here.

Copy link
Member

@yurishkuro yurishkuro left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

There are two noteworthy disadvantages of introducing an Optional type:

1. Since the type isn't standard, external packages working with config may
require additional adaptations to work with our config structs.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we give examples of external packages working with config? E.g. validation libs come to mind, but they might still work, for them Optional is just an extra nesting container.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm mostly concerned about something like #10694, where we want to generate config types from a JSON schema. I'm not sure how this would treat optional types.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok, but how do you want to move the discussion forward? Just take a vote? Or do more cost/benefit analysis, and potentially block this on unresolved #10694?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We'll essentially need a vote to get this merged anyway per the Collector's RFC process, so I think that's what it will come down to.

I think this is far more straightforward than #10694 anyway, so I would prefer to not block it on that. I'm just calling it out here as a risk.

Copy link
Member

@bogdandrutu bogdandrutu left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

be used as a type parameter to `Optional[T]`. The following config struct shows
how this may look, both in definition and in usage:

```golang
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More than golang code, would be good to show how users in yaml will use it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there's no expected impact on YAML

Comment on lines +28 to +36
2. The distinction between values that are conventionally pointers (e.g. gRPC
configs) and optional values is lost.
3. Setting a default value for a pointer field when decoding will set the field
on the resulting config struct, and additional logic must be done to unset
the default if the user has not specified a value.
4. The potential for null pointer exceptions is created.
5. Config structs are generally intended to be immutable and may be passed
around a lot, which makes the mutability property of pointer fields
an undesirable property.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Drawback numbers 2 and 5 appear contradictory. Is there a reason why pointers are "conventionally" pointers, aside from mutability?

Suggested change
2. The distinction between values that are conventionally pointers (e.g. gRPC
configs) and optional values is lost.
3. Setting a default value for a pointer field when decoding will set the field
on the resulting config struct, and additional logic must be done to unset
the default if the user has not specified a value.
4. The potential for null pointer exceptions is created.
5. Config structs are generally intended to be immutable and may be passed
around a lot, which makes the mutability property of pointer fields
an undesirable property.
2. While they can be copied cheaply, pointers convey a mutable reference making
them unsafe to share.
3. Setting a default value for a pointer field when decoding will set the field
on the resulting config struct, and additional logic must be done to unset
the default if the user has not specified a value.
4. The potential for null pointer exceptions is created.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This may not really apply to config structs, but outside mutability, another reason to use a pointer type for a field in Go is so you don't have to pass around a large struct by value.

The specific point I was making with item 2 is that some types in popular libraries are pointers, e.g. *zap.Logger, *grpc.Server, etc. If pointers are used to indicate optional values, if you have a field that is a *zap.Logger type, it's difficult to tell if it's intentionally optional, or if that type is almost always used as a pointer type (zap.Logger as a non-pointer is rare from what I've seen). Obviously *zap.Logger isn't a perfect example because nobody is setting a logger in YAML, but hopefully my point still makes sense.

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.

6 participants