The short answer is yes, but not in this example. In your example the inline doesn't happen because `foo` is (barely) too complex so it is not inlined and the closure remains a parameter: ``` go build -gcflags=-m=2 main.go # command-line-arguments ./main.go:3:6: cannot inline foo: function too complex: cost 82 exceeds budget 80 ./main.go:13:6: cannot inline main: function too complex: cost 87 exceeds budget 80 ./main.go:15:12: can inline main.func1 with cost 6 as: func(int) bool { return v % 2 == 0 } ./main.go:4:16: make([]int, 0, len(data)) escapes to heap: ./main.go:4:16: flow: {heap} = &{storage for make([]int, 0, len(data))}: ./main.go:4:16: from make([]int, 0, len(data)) (non-constant size) at ./main.go:4:16 ./main.go:3:10: data does not escape ./main.go:3:22: suitable does not escape ./main.go:4:16: make([]int, 0, len(data)) escapes to heap ./main.go:14:15: []int{...} does not escape ./main.go:15:12: func literal does not escape ```
I simplified your `foo` to take result as a parameter, and that did the job: ``` go build -gcflags=-m=2 main.go # command-line-arguments ./main.go:3:6: can inline foo with cost 74 as: func([]int, []int, func(int) bool) []int { for loop; return result } ./main.go:12:6: cannot inline main: function too complex: cost 113 exceeds budget 80 ./main.go:15:20: can inline main.func1 with cost 6 as: func(int) bool { return v % 2 == 0 } ./main.go:15:5: inlining call to foo ./main.go:15:5: inlining call to main.func1 ./main.go:3:16: parameter result leaks to ~r0 with derefs=0: ./main.go:3:16: flow: ~r0 = result: ./main.go:3:16: from return result (return) at ./main.go:9:2 ./main.go:3:10: data does not escape ./main.go:3:16: leaking param: result to result ~r0 level=0 ./main.go:3:30: suitable does not escape ./main.go:14:16: make([]int, 0, len(data)) escapes to heap: ./main.go:14:16: flow: {heap} = &{storage for make([]int, 0, len(data))}: ./main.go:14:16: from make([]int, 0, len(data)) (non-constant size) at ./main.go:14:16 ./main.go:13:15: []int{...} does not escape ./main.go:14:16: make([]int, 0, len(data)) escapes to heap ./main.go:15:20: func literal does not escape ``` You can examine the output either with `-S` ``` go build -gcflags=-S main.go > main.asm ``` or with `GOSSAFUNC=main` ``` GOSSAFUNC=main go build main.go # runtime dumped SSA for main,1 to ../../src/inline-lam/ssa.html # command-line-arguments dumped SSA for main,1 to ./ssa.html ``` and in either case you will see that the call to foo and the closure are gone. With PGO ( https://go.dev/doc/pgo ) if that function (foo) is on a hot path, it is more likely to get inlined and thus allow the closure inlining. (and if it's not on a hot path, do you care?) On Monday, October 23, 2023 at 12:19:51 PM UTC-4 Shamil Mukhetdinov wrote: > Imagine you have something like this: > > * func foo(data []int, suitable func(v int) bool) []int { * > * result := make([]int, 0, len(data) * > * for _, v := range data { * > * if suitable(v) { * > * result = append(result, v) * > * } * > * } return result * > *} * > > > func main() { > data := []int{1, 2, 3, 4, 5} > foo(data, func(v int) bool { return v % 2 == 0 }) > } > > If instead of suitable lambda I use an explicit function call, that call > may be inlined in Go. > > But C++ supporting inlining for copied closures. > > Does golang support inlining for lambdas, if I have that function > signature? Or only non-escaping to the other functions lambdas can be > inlined? > > I found this issue which is still open > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/golang-nuts/fee35c70-d93a-4b6d-9106-b8286372cb4bn%40googlegroups.com.