0

Having programmed a whole lot in python, using nested functions is a good way to not clutter the namespace with small helper functions that are only used once.

Now I'm programming in go, and upon writing some code that I immediately wanted to refactor into an inner function, I found that go does not allow nested function declarations. I immediately changed the function to an anonymous function and saved it in a variable, and called it as a normal function. However, this seems to go against the language design since the normal function declaration syntax cannot be used inside another function.

Is there a good reason to not allow, or to deter use of nested function declarations?

4
  • 2
    I think the answer is here. stackoverflow.com/questions/21961615/…
    – yfklon
    Jul 13 '15 at 14:29
  • Yes, this is a duplicate of that question. Those answers answer this question, unless the go language developers have issued some statement on this since. Jul 13 '15 at 14:34
  • 3
    This should be closed for being a duplicate of this.
    – Neil
    Jul 13 '15 at 14:37
  • 1
    @Neil it can only be a duplicate if the other question is on the current site.
    – user22815
    Jul 14 '15 at 3:04
7

Go's primary design goal is to be simple to learn and simple to use even for sub-mediocre programmers, so if you want to write idiomatic Go the anti-pattern you should avoid the most is the "Clever Code" anti-pattern.

As for a good reason to not allow nested functions even though you allow anonymous functions - one of the differences between Python and Go is that Python doesn't need a main function. You can just write:

def foo():
    print('hi')

foo()

and the Python interpreter would start reading from top to bottom. When it reaches def foo(): it will create a function, and when it reaches foo() it'll run that function. The interpreter is always in the same mode(that's, at least, the abstraction) - the read-and-evaluate mode. It acts the same whether it's inside or outside a function, so it's easy for it to support copying all that code to inside a function - it'll just add another frame to it's callstack and other than that do the exact same thing.

Go is a different story. When you write

func foo() {
    fmt.Println("hi")
}

func main() {
    foo()
}

The compiler reads the top level in declarative mode, and creates the functions, but the body of the functions it reads in imperative mode. In declarative mode it can create functions and in imperative mode it can run statements. Allowing nested functions will require adding function declaration functionality to imperative mode.

So why, one might ask, not add that functionality to imperative mode? The main reason is handling closures:

func main() {
    txt := "hi"
    foo := func() {
        fmt.Println(txt)
    }
    foo()
}

Writing something like this means that foo is not a regular function - it needs access to txt, which resides in main's stack frame, so it needs a context pointer that'll point to that frame. If main is called again another foo will be created with a different context pointer.

This makes nested functions essentially different from regular functions, which is a reason against having nested functions. Python doesn't have this problems, because all it's functions are closures - they are all "nested".

0

The behavior and semantics of nested functions are much closer to anonymous functions than to non-nested functions. Most likely, they simply wanted the syntax to reflect that difference.

However, it wouldn't surprise me to see nested functions in a future update, because I believe the reasons are more cultural than technical. Go was intended as a successor to C-family languages for systems programming. The previous dominant languages for that purpose didn't support nested functions, and so programmers who work in those areas haven't incorporated nested functions into their design idioms.

To many programmers, that kind of encapsulation at the function level doesn't "feel" right. To them, encapsulation of helper functions is the job of a class, end of story. This is a deeply-ingrained, reflexive attitude among many object-oriented programmers. You'll see this if you ever work somewhere that does mostly C++ programming with some python utilities on the side.

I think this attitude is slowly changing as functional-style features are being added to "enterprise" languages, but it might take a couple generations.

Not the answer you're looking for? Browse other questions tagged or ask your own question.