Reliability and safety
evalorder
Checks later operands that mutate values evaluated earlier.
What it detects
Function arguments and return operands are evaluated from left to right. Split an operation into statements when a later operand mutates a value already read by an earlier operand.
Checks
| Check | What it detects |
|---|---|
operand-mutation |
Reports expressions whose later operand mutates a value read by an earlier operand. |
Why this is flagged
Combining a read and a mutation in one expression makes the result depend on a subtle evaluation-order rule. Separate statements make the intended old and new values obvious and prevent surprising results during later edits.
Further reading: The Go specification: Order of evaluation.
How to fix it
Split the expression into separate statements. Save any value that must be read before the mutation, perform the mutation, and then pass or return the named results in their intended order.
Examples
Flagged code
func refresh(value *int) error { *value = 42 return nil}
func load(value int) (int, error) { // gohawk: later operand may mutate value after its earlier value was evaluated return value, refresh(&value)}Accepted code
func refreshSafely(value *int) error { *value = 42 return nil}
func loadInOrder(value int) (int, error) { err := refreshSafely(&value) return value, err}