Here we have an apparent conflict between two idioms:
The Comma, Ok Idiom with If Statement: limiting the scope of variables to only where they are needed, frequently used for error handling and type assertions.
Avoiding unnecessary else blocks after an if block that ends with a return statement to reduce nesting and improve readability.
var bs []byte
if bs, err = json.Marshal(b); err != nil {
handleError(w, err)
return
}
fmt.Fprintln(w, string(bs))
Moving âbsâ outside/above the if statement increases its scope and could result in a bug.
Golint sides with idiom #2:
if block ends with a return statement, so drop this else and outdent its block (move short variable declaration to its own line if necessary)
Notes
Context matters, for smaller functions where the broader scope of a variable does not significantly increase complexity or risk, simplifying control flow by avoiding unnecessary else blocks might be preferred. In more complex functions, or when a variable genuinely should not be accessible beyond a specific block of code, maintaining tighter scope might be prioritized.
golint provides suggestions based on common best practices, but it doesnât encompass all possible contexts or nuances of code. Itâs a tool to aid development, not a strict set of rules that must be followed in every situation.
Is Golint thus the authoritative answer making #2 the more idiomatic choice?
This does seem to be a very popular way of doing it. The benefit is ease and clarity by using the shorthand declaration for âbsâ as well, and not having to look up and specify its type (similar to option #1 in my post). The trade-off is that this also increases the scope of âerrâ.
This is plenty idiomatic and if you look at the go source youâll see it all over the place. For example in encoding/json:
// convertNumber converts the number literal s to a float64 or a Number
// depending on the setting of d.useNumber.
func (d *decodeState) convertNumber(s string) (any, error) {
if d.useNumber {
return Number(s), nil
}
f, err := strconv.ParseFloat(s, 64)
if err != nil {
return nil, &UnmarshalTypeError{Value: "number " + s, Type: reflect.TypeFor[float64](), Offset: int64(d.off)}
}
return f, nil
}
This is something I didnât consider. The idiomatic way to do it depends on whether you need to do further processing on the return values of the variables involved in the Comma, Ok idiom.
Thank you! How did I not think about looking for examples in the standard library? Although there are some pretty whimsical examples in there (yes, sort package, Iâm looking at you!).