118

Lambdas work as expected:

func main() {
    inc := func(x int) int { return x+1; }
}

However, the following declaration inside a declaration is not allowed:

func main() {
    func inc(x int) int { return x+1; }
}

For what reason are nested functions not allowed?

TylerH
  • 20,816
  • 57
  • 73
  • 92
corazza
  • 30,052
  • 35
  • 108
  • 182
  • hmm I dont know if you meant to do this `func main() { func (x int) int { return x+1; }(3) }` – ymg Feb 22 '14 at 22:48
  • @YasirG. but that's a lambda as well, isn't it? I don't get your comment... – corazza Feb 22 '14 at 22:50
  • what functionality will enabling the second example in the syntax allow, that is not supported by the first case? – Not_a_Golfer Feb 22 '14 at 22:55
  • @yannbane it is a lambda expression, I don't think you can declare a function inside another function like JS. So I'd say your best fit is to use lambdas. – ymg Feb 22 '14 at 22:58
  • @Not_a_Golfer: One possibility would be to implement it the way JavaScript does, essentially assigning a function to a variable is very different than declaring a function because of the flow of control affects such variables, while functions in JavaScript do not get affected. That means that you could call `inc()` in the second example before the actual declaration. But! I'm looking for reasons, I don't know much about Go but I would like to learn what the logic behind this rule was. – corazza Feb 22 '14 at 22:59
  • @YasirG.: yes I know, I'm not actually programming Go right now, and if I were lambdas would suit me just fine. I'm wondering about why the designers chose to make it this way and not the other, that's all. – corazza Feb 22 '14 at 23:00
  • Well, if there's one thing I wouldn't take from JS is the scope mess :) Also keep in mind that Go is compiled, functions that are not lambdas are not created in runtime. in JS everything is created in runtime. – Not_a_Golfer Feb 22 '14 at 23:05
  • @yannbane I don't see how changing the declaration system would make things different, I pretty much agree with **Not_a_Golfer** here. I heard this multiple times from the Go dev team, they don't want multiple declaration syntax of everything which causes massive mess in the long run. – ymg Feb 22 '14 at 23:07
  • @Not_a_Golfer funny thing is that Rob Pike made a funny comment about how JS/Ruby/Python devs have almost no concept of scope. https://twitter.com/rob_pike/status/402853302464831488 – ymg Feb 22 '14 at 23:09
  • @Not_a_Golfer oops I was referring to this tweet -> https://twitter.com/rob_pike/status/402853390973026305 – ymg Feb 22 '14 at 23:14
  • @YasirG. to be fair, Python is pretty strict about scopes most of the time, you can't even assign to a global variable within a function without the `global` keyword, and it's rarely used. The only cases that cause confusion are static vs. instance members. – Not_a_Golfer Feb 22 '14 at 23:20
  • possible duplicate of [Does Go have lambda expressions or anything similiar?](http://stackoverflow.com/questions/11766320/does-go-have-lambda-expressions-or-anything-similiar) – mcuadros Feb 22 '14 at 23:49
  • Why the downvotes? I did try to research but all I came up with was a Google Groups thread asking the same thing but with no useful answers. If it was unclear, I've edited it now. I don't see how it would be "not useful" - there could be interesting problems that could arise from such nested functions... – corazza Feb 23 '14 at 00:17
  • Also what exactly are the scoping issues people are talking about? Does someone have a summary that shows what Go does differently and how is that better? I'm searching myself but if you had a nice source that would help. – corazza Feb 23 '14 at 00:21
  • Found something on JavaScript scoping issues: http://dailyjs.com/2012/07/23/js101-scope/. – corazza Feb 23 '14 at 20:53
  • I would just like to add that the question proposed as a duplicate does not ask the same thing! – corazza Feb 24 '14 at 10:31
  • @jcora old post, but for the record: "That means that you could call inc() in the second example before the actual declaration" > this is specific to Javascript and usually called function declaration hoisting. Golang (like most other programming languages) does not hoist function declarations. I think it's a good thing (less confusion) but anyway, that's the choice that was made. – Greg May 14 '17 at 06:05
  • 1
    One problem this would solve is recursive nested functions, see https://github.com/golang/go/issues/226 – Peter Dotchev May 10 '18 at 19:44
  • 1
    Asking the "why" of language design decisions is off-topic, as it's an opinion that only the language designers can answer. Asking how to work around such limitations is, of course, on-topic here. – Flimzy Feb 16 '20 at 17:57
  • @Flimzy we can have a discussions about the reasons behind design choices. These things aren't incommunicable – corazza Feb 19 '20 at 17:52
  • 1
    @corazza: No, they're not incommunicable. They're just off-topic. – Flimzy Feb 20 '20 at 08:18

6 Answers6

72

I think there are 3 reasons why this obvious feature isn't allowed

  1. It would complicate the compiler slightly. At the moment the compiler knows all functions are at the top level.
  2. It would make a new class of programmer error - you could refactor something and accidentally nest some functions.
  3. Having a different syntax for functions and closures is a good thing. Making a closure is potentially more expensive than making a function so you should know you are doing it.

Those are just my opinions though - I haven't seen an official pronouncement from the language designers.

Nick Craig-Wood
  • 50,914
  • 12
  • 120
  • 124
  • 2
    Pascal (at least it's Delphi incarnation) got them right and simple: the nested functions behave just like regular but also have access to the variables in their enclosing function's scope. I do not think these are hard to implement. On the other hand, having written lots of Delphi code I'm not sure I badly need nested functions: occasionally they feel nifty but they tend to blow the enclosing function making it hardly readable. Also accessing the arguments of their parents may make the program hard to read since these variables are accessed implicitly (not passed as formal parameters). – kostix Feb 23 '14 at 17:41
  • 1
    local functions are great as an intermediate refactoring step on your way to extract methods. In c# they have made these more valuable once they introduced static local functions which are not allowed to capture variables from enclosing function so you are forced to pass anything as parameter. Static local funcitons make point 3 a non-issue. Point 2 is also a non-issue from my point of view. – Cosmin Sontu Jul 11 '19 at 10:17
59

Sure they are. You just have to assign them to a variable:

func main() {
    inc := func(x int) int { return x+1; }
}
Matt Williamson
  • 37,633
  • 10
  • 61
  • 71
31

Frequently Asked Questions (FAQ)

Why does Go not have feature X?

Every language contains novel features and omits someone's favorite feature. Go was designed with an eye on felicity of programming, speed of compilation, orthogonality of concepts, and the need to support features such as concurrency and garbage collection. Your favorite feature may be missing because it doesn't fit, because it affects compilation speed or clarity of design, or because it would make the fundamental system model too difficult.

If it bothers you that Go is missing feature X, please forgive us and investigate the features that Go does have. You might find that they compensate in interesting ways for the lack of X.

What would justify the complexity and expense of adding nested functions? What do yau want to do that you can't do without nested functions? Et cetera.

peterSO
  • 146,831
  • 29
  • 256
  • 250
  • 20
    To be fair, I don't think anyone's demonstrated any particular complexity that allowing nested functions would cause. Plus, while I agree with the quoted philosophy, I'm not sure it's reasonable to refer to nested functions as a "feature," so much as referring to their omission as a feature. Do you know of any complications that allowing nested functions would allow? I'm assuming they'd just be syntactic sugar for lambdas (I can't think of any other reasonable behavior). – joshlf Feb 23 '14 at 06:30
  • Since go is compiled, the only way to do this AFAIK, will create another syntax for defining lambdas. And I really don't see a use case for that. you can't have a static function within a static function created in real time - what if we don't enter the specific code path that defines the function? – Not_a_Golfer Feb 23 '14 at 08:52
  • Simply pass in lambda interface{} and type assert. Eg. f_lambda := lambda(func()rval{}) or whatever the prototype would be. The func decl syntax does not support this but the language totally does. – BadZen Apr 27 '15 at 05:36
21

Here's a way to implement nested functions and functions within nested functions

package main

import "fmt"

func main() {

    nested := func() {
        fmt.Println("I am nested")

        deeplyNested := func() {
                fmt.Println("I am deeply nested")
            }

        deeplyNested()
    }

    nested()
}
fuz
  • 82,933
  • 24
  • 182
  • 332
Koala3
  • 2,089
  • 3
  • 19
  • 15
12

Nested functions are allowed in Go. You just need to assign them to local variables within the outer function, and call them using those variables.

Example:

func outerFunction(iterations int, s1, s2 string) int {
    someState := 0
    innerFunction := func(param string) int {
        // Could have another nested function here!
        totalLength := 0
        // Note that the iterations parameter is available
        // in the inner function (closure)
        for i := 0; i < iterations; i++) {
            totalLength += len(param)
        }
        return totalLength
    }
    // Now we can call innerFunction() freely
    someState = innerFunction(s1)
    someState += innerFunction(s2)
    return someState
}
myVar := outerFunction(100, "blah", "meh")

Inner functions are often handy for local goroutines:

func outerFunction(...) {
    innerFunction := func(...) {
        ...
    }
    go innerFunction(...)
}
vthorsteinsson
  • 342
  • 2
  • 5
-1

You just have to call it immediately by adding () to the end.

func main() {
    func inc(x int) int { return x+1; }()
}

Edit: cannot have function name...so it's just a lambda func getting called right away:

func main() {
    func(x int) int { return x+1; }()
}
Nick
  • 395
  • 3
  • 12
  • 1
    Uhh that doesn't conform to what one would expect of a function definition – corazza Feb 16 '18 at 18:12
  • 1
    @corazza Ah, I missed the word "declaration" when I read the question. My bad. – Nick Feb 21 '18 at 22:54
  • 1
    @corazza Also, I screwed up the syntax too. Needed to remove the function name. So, it's basically a lambda function that is called immediately. – Nick Feb 21 '18 at 23:05