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.

Reply via email to