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
Rework flag tags to allow for easier extensibility #6246
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mind updating the PR description with a bit more context / motivation as well as a high-level summary of the changes? There is a lot of code being moved around and I'm not familiar enough with this part of the code to grasp what's happening in this PR after a first pass :)
Of, course, no problem! |
Make tags extensible without needing to special-case each new tag type that needs to modify methods.
Go
flag.Value
s need to be able to produce accurate string forms of their zero values even when the instance is nil because of how they are used inflagset.Usage
:https://cs.opensource.google/go/go/+/refs/tags/go1.22.1:src/flag/flag.go;l=642-644
This means if we are wrapping a value, we need to capture the type of the value in a type parameter of the wrapping type. Unfortunately, that means that if we want the
Tag
function of a tag we pass in to theNew
orVar
functions would need to have a type parameter as well if we needed them to wrap the flag value themselves, resulting in the awkward and repetitive:where
SecretTag[T any]
would have aTag
method that would wrap the flag in question in aSecretFlag[T]
.To avoid this, I had been custom-recognizing the tag types that need to wrap flags inside of
Var[T]
and just ignoring their tag methods and doing the wrapping there. However, ideally creating a new tag doesn't require this weird special-casing. To that end, I have createdTagFlag[T]
which can be created by theTag[T]
function to wrap flag values and then be passed to theTag
method of a tag as aTagged
. The method can then freely modify the functions by usingTagged
's interface to set functions without needing to parameterize the type of the tag or createflag.Value
s that cannot satisfy the requirement of producing valid strings when nil.I did all this when I was adding a new
Hidden
flag tag for buildbuddy-io/buildbuddy-internal#2804 and then realized I was going to have to add yet another special case to the tag for loop inVar[T]
.This also prevents duplication of code and boilerplate for every tag-flag-value-type, as can be seen with how it allows
Secret
andDeprecate
to both be defined using TagFlag. It should, generally, also make it easier to define new tags without touchingflagutil
at all.Related issues: N/A