12
votes

My understanding of short circuit evaluation is that an expression is only called when needed in an if statement. Does Go follow this?

For instance, would I get better performance on average from:

if !isValidQueryParams(&queries) || r == nil || len(queries) == 0 {
    return "", fmt.Errorf("invalid querystring")
}

...to this:

if r == nil || len(queries) == 0 || !isValidQueryParams(&queries) {
    return "", fmt.Errorf("invalid querystring")
}

...since isValidQueryParams is a function with much more overhead than r == nil or testing the length of a map?

i.e. will the interpreter evaluate r == nil first, see it's true and not bother to evaluate the other conditions?

EDIT: Incorrectly referred to short circuit evaluation as lazy evaluation

3
I think lazy evaluation usually refers to a variable whose value isn't calculated or fetched (from a DB or API, for example) until it's accessed.Flimzy
Somewhat related: there is short circuit evaluation in Go code, but Go's template engine does not use short circuit evaluation. Details: Golang template and testing for Valid fieldsicza
@icza, thanks, included.kostix

3 Answers

13
votes

Thank you to Kostix and mkrieger for their answers - they are correct, I'm referring to short circuit evaluation and not lazy evaluation.

Go does implement normal short circuit evaluation, as can be deduced with the following code:

package main

import "fmt"

func main() {
    for i := 0; i < 10; i++ {
        if testFunc(1) || testFunc(2) {
            // do nothing
        }
    }
}

func testFunc(i int) bool {
    fmt.Printf("function %d called\n", i)
    return true
}

...which will always give:

$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
$ function 1 called
10
votes

This is called short circuit evaluation. According to this tutorial, the boolean operators use this:

Although in the Go language specification it does not explicitly state that Go uses short circuit evaluation, it does mentiong that

Logical operators apply to boolean values and yield a result of the same type as the operands. The right operand is evaluated conditionally.

Here is a quick example to prove that Go uses short circuit evaluation

[…]

7
votes

What you're referring to is called "short circut evaluation"—that is, the subexpressions are evaluated using the normal associativity rules only for as long as the complete result is available and evaluation of the rest of the expressions won't change it according to the rules of the binary operator(s) in question.

Go does implement short circuit evaluation of logical expressions (see the other answer).

(@icza commented: Somewhat related: there is short circuit evaluation in Go code, but Go's template engine does not use short circuit evaluation. Details: Golang template and testing for Valid fields.)

"Lazy evaluation" is completely another thing—usually implemented in the so-called "functional" programming languages, and it's not directly implemented in Go.


Having said that, I'd note that while Go does not have direct (as with the syntax and runtime) support for lazy evaluation, it may be used where needed.

For instance, you may have a goroutine reading potentially infinite number of items from a channel, and processing them in one way or another, and another goroutine—or several of them—producing these values and sending them through the channel. This way, the values only "materialize" at the receiving end no faster than they are actually ready to be handled.