Skip to content
Reliability and safety

evalorder

Checks later operands that mutate values evaluated earlier.

Fix offeredNo

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
}