130

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,799
  • 66
  • 75
  • 101
corazza
  • 31,222
  • 37
  • 115
  • 186
  • 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. – Jonathan Hall 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. – Jonathan Hall Feb 20 '20 at 08:18
  • 1
    @JonathanHall Getting to know about the reasons for design related things definitely helps developers, especially when these days almost all of us work with multiple languages. I don't understand how it is off-topic. – manisar Jun 20 '23 at 17:57
  • @manisar: Nobody said it's not helpful. But not all helpful things are on-topic on Stack Overflow. You can read more about this decision [here](https://meta.stackoverflow.com/q/323334/13860) – Jonathan Hall Jun 21 '23 at 07:42
  • 1
    @JonathanHall thanks, yes, the link explains it. But there may be an official answer in which case such a question-answer pair shouldn't be off-topic. The asker cannot know at the time of asking if there is or isn't an official answer (else they simply wouldn't ask), so the question should be allowed I guess. Secondly - just my view - even if there isn't an official answer, by marking such a programming-related question as 'off-topic' or closing it as 'opinion-based', we'll be depriving developers of a really helpful piece of information the likes of which we hope to get from SO. – manisar Jun 21 '23 at 18:08
  • @manisar: If you've read the link I shared, the existence of an official answer does not change the fact that it's off-topic. Further, whether the OP knows something is off-topic when they ask it is also irrelevant to the definition of off-topic. – Jonathan Hall Jun 21 '23 at 18:43
  • 1
    Oh yes @JonathanHall, that was dumb of me to raise the *official-answer-exists-so-why-off-topic question* in light of the link you had shared. Although I do not agree with the philosophy of marking such questions as off-topic, but that is a separate concern and is to be raised elsewhere. Thanks for your time and patience. – manisar Jun 22 '23 at 21:36

5 Answers5

75

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
  • 52,955
  • 12
  • 126
  • 132
  • 6
    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
  • By supporting nested structure declarations, Go invalidates points #1 and #2. Structures can be defined inside functions which means scoping types and making the distinction between top level and others meaningless. It also makes the new class of programmer error possible when refactoring structures. – Tenders McChiken Aug 22 '23 at 08:55
29

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
  • 158,998
  • 31
  • 281
  • 276
  • 21
    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
22

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
  • 88,405
  • 25
  • 200
  • 352
Koala3
  • 2,203
  • 4
  • 20
  • 15
13

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
  • 352
  • 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
  • 405
  • 4
  • 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