-
Notifications
You must be signed in to change notification settings - Fork 17.5k
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
proposal: flag: add Strings, a default Value #40155
Comments
As it happens, in 2015 we added exactly this API (same names and everything) to our internal library at my company. It got a lot of use and it works well enough. During those five years, though, we found that there is a downside: this The reason this happens is because of code like this:
Of course you can always avoid this by declaring the
but in practice, people usually end up doing the former because it's shorter and more direct. A month ago I changed our API to the following:
(Essentially, this is taking the This is a smaller API and lets us do what we want more directly, which is to have the flag directly manipulate a
|
While it may not be as intuitive to beginners, types have call site usage that feels like a pseudo function. As such, and I think the utility of the exported type can justify this otherwise arcane syntax: (though it would be nice if you could var c conf
flag.Var((*flag.Strings)(&c.things), "thing", "Specify things (may be given multiple times)")
flag.Parse() I am also unclear how your package flag
func Strings(name string, value string, usage string) *[]string
func StringsVar(p *[]string, name string, value string, usage string) |
@ianlancetaylor: can you add this to the proposals project? |
@carnott-snap Done. |
As I understand it, this issue is asking for a way in the standard flag package to support flags that accumulate string values, like:
which would end up with a value []string{"abc", "def"} somehow, like the Go compiler's -I flags. The way that would fit into the flag package would be not to define a new type but to define The three questions then are:
|
|
I literally have a Github package with flagext.Strings, but I am -0 on this feature request. First of all, my package gets around the "leaky type" problem by having another helper Second, the default value is hard to make work with current flag package conventions. Third, mystrings := []string{"a", "b"}
flag.Func("s", "some help", func(s string) error {
mystrings = append(mystrings, s)
return nil
}) Since the semantics of flag.Strings are a little hard to specify (e.g., should it use comma splitting or multiple invocation and should it copy default flags or append in place), I think it's best left to package users, like flag.File (see my rejected proposal in #23284). |
FWIW, rather than a (Also, I came here because I was confused whether this was about repeated/comma-separated strings or something like an enum-field) |
The new flag.Func does work well for this, as @carlmjohnson points out. That's how we implement Given that we only recently added flag.Func, it seems like we should probably slow down and not start adding even more things. flag.Func makes this use case much more convenient. |
Based on the discussion above, this seems like a likely decline. |
An alternative implementation would be a reflection based api. func SliceVar(slice interface{}, name, usage string) |
No change in consensus, so declined. |
I also have (since 2018) a more generic and more powerful version that handles slices of any types as a func Slice(sl interface{}, separator string, parse func(string) (interface{}, error)) Value See: github.com/dolmen-go/flagx.Slice The |
proposal
While there are certainly many custom
flag.Value
implementations that are required, most of the time, all I want is a[]string
. As such, I suggest we add aflag.Strings
symbol:costs
It is another symbol on the flag package, so it could get lost or be confusing, however I think this will serve to improve customer code considering how much this is implemented, like
sort.StringSlice
. My biggest concern is if everybody needs a different implementation.alternatives
If, as @cespare calls out, we are concerned about this custom type proliferating, we can instead expose a constructor: (see below)
Unfortunately, this
flags.Strings
does not work the same asflag.String
and simply mirroring that interface seems better:extensions
Because it is easier, I have assumed that all
flag.Strings
will have the default of emptiness. If it is preferred, we could instead return the first element or a csv joined form of all elements:If the use case can be justified, it may be worth adding some state and complexity to Strings, but without a clear litmus, it is hard to know where to stop:
That being said, there are real flexibility benefits to hiding the implementation in a struct:
The text was updated successfully, but these errors were encountered: