26

Why can't I define a recursive function as a variable? I seem to be able to define arbitrary functions except when they recurse.

This is legal:

func f(i int) int {
    if i == 0 {
        return 1
    }
    return i * f(i-1)
}

func main() {
    fmt.Println(f(2))
}

This is illegal:

var f func(int) int = func(i int) int {
    if i == 0 {
        return 1
    }
    return i * f(i-1)
}

func main() {
    fmt.Println(f(2))
}

This is legal and I'm guessing it is just because you can figure out f after initialization:

func main() {
    var f *func(int) int;
    t := func(i int) int {
        if i == 0 {
            return 1
        }
        return i * (*f)(i-1)
    }
    f = &t
    fmt.Println((*f)(2))
}

So it looks like it comes down to function and variable declarations of a function type are treated differently though from the reading the documentation I wouldn't expect that to be the case. Did I miss the part of the documentation detailing this?

I would expect the illegal case to work just because it works in other languages. Like in JavaScript:

(function () {
  var f = function (i) {
    if (i == 0) {
      return 1;
    }
    return i * f(i - 1);
  };

  console.log(f(2));
})();
2
  • 3
    Go is not Javascript. Javascript looks at your code and says "that looks ok, I don't know what f is yet, but I probably will by the time this block is called", and then assigns the function to the variable f, and everything is good. Go wants to know what f is first before it encounters code that calls it. Commented Feb 17, 2015 at 22:50
  • That is what is happening but doesn't really say why. Go doesn't want to know what f is if f is declared as a function but Go does want to know if f is declared as a function type variable. That's what is weird. Commented Feb 17, 2015 at 23:00

1 Answer 1

49

The below code would be the preferred way of doing what you describe. Note that you do not have to create an additional variable, nor do you have a pointer to a function:

package main

import "fmt"

func main() {
    var f func(int) int
    f = func(i int) int {
        if i == 0 {
            return 1
        }
        return i * f(i-1)
    }
    fmt.Println(f(2))
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thanks that's a much better working solution. I am hoping for some documentation that points this out. It does seem to be very strange that functions and variables of function types are treated so differently.
@DanielWilliams: From the spec: The scope of a constant or variable identifier declared inside a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl for short variable declarations) and ends at the end of the innermost containing block. That means that the fidentifier is not valid until the value is fully defined. This is why you cannot do in Go what you do in JavaScript.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.