Skip to content

Value's that implement IsBoolFlag() always show a default value #360

@twelvelabs

Description

@twelvelabs

I've implemented a custom Value type for managing generic data. Everything works as it should, but the flags always show a default in their usage string regardless of whether they have a zero value:

type Value struct {
    data     interface{}
    dataType string
}

func (v *Value) String() string {
    return cast.ToString(v.Get())
}

func (v *Value) Get() interface{} {
    return v.data
}

func (v *Value) Set(data string) error {
    // validates, casts, and sets v.data using v.Type()
}

func (v *Value) Type() string {
    return v.dataType
}

func (v *Value) IsBoolFlag() bool {
    return v.Type() == "bool"
}


func main() {
    value := &Value{
        data: "",
        dataType: "string",
    }
    pflag.Var(value, "project-name", "Some usage text")
    pflag.Parse()
    // Prints:
    // --project-name string   Some usage text (default "")
    pflag.Usage()


    flag := pflag.Lookup("project-name")
    // Prints:
    // default: '', isZero: false
    fmt.Printf("default: %q, isZero: %v", flag.DefValue, flag.defaultIsZeroValue())
}

The issue seems to be caused here - by checking for whether the value implements the boolFlag interface (rather than the return value of IsBoolFlag()):

pflag/flag.go

Lines 536 to 541 in d5e0c06

// defaultIsZeroValue returns true if the default value for this flag represents
// a zero value.
func (f *Flag) defaultIsZeroValue() bool {
switch f.Value.(type) {
case boolFlag:
return f.DefValue == "false"

Seems like the fix would be to move the boolFlag check prior to the switch statement and have it actually call IsBoolFlag(), like so:

    if bf, ok := f.Value.(boolFlag); ok && bf.IsBoolFlag() {
        return f.DefValue == "false"
    }
    switch f.Value.(type) { ... }

Then custom values would make it through to the default case in the switch statement.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions