Bug
Let's take a look at the following program and think about what the output should be?
func main() {
n := 0
f := func() func(int, int) {
n = 1
return func(int, int) {}
}
g := func() (int, int) {
println(n)
return 0, 0
}
f()(g())
}
Think for a few seconds. . .
Before Go 1.13, the result printed by the above program was
1
Starting with Go 1.13, the result printed by the above program is
0
From a habitual cognition point of view, the compiler should execute in the following order
- step 1: evaluate
f()
, the value of the variablen
is 1 - step 2: evaluate
g()
, when printingn
, because step 1 has changedn
to 1, it should print 1 - step3: Execute the final function call based on the results of step 1 and step 2
The Go compiler actually follows this design. The official documentation describes it as follows:
At package level, initialization dependencies determine the evaluation order of individual initialization expressions in variable declarations .
Otherwise, when evaluating the operands of an expression, assignment, or return statement , all function calls, method calls, and communication operations are evaluated in lexical left-to-right order.
The expression of the last sentence shows that when a function call is executed, the operands of the function are parsed from left to right grammatically.
This bug was actually proposed by Matthew Dempsky , a member of the Google Go team. Go officially claimed this bug . The reason for this bug is also obvious. It was executed first g()
, and then executed f()
.
This is because we rewrite
f()(g())
intot1, t2 := g(); f()(t1, t2)
during type checking.gccgo compiles it correctly.
@cuonglm Yeah, rewriting as
t0 := f(); t1, t2 := g(); t0(t1, t2)
instead seems like a reasonable quick fix to me. I think direct function calls and method calls are probably the most common case though, so we should make sure those are still handled efficiently.Longer term, I think we should probably incorporate order.go directly into unified IR.
The current scope of the bug is as follows:
- This bug, introduced in Go version 1.13, has been fixed and is expected to be released in version 1.19.
- Only the official compiler
gc
has this bug, and if you are using thegccgo
compiler, it will not have this problem. - This bug occurs only for function calls with multiple parameters. For example, the result of the following example
f()
is a function that has only one parameter, so the bug mentioned in this article will not exist.
package main
func main() {
n := 0
f := func() func(int) {
n = 1
return func(int) {}
}
g := func() int {
println(n)
return 0
}
f()(g())
}
The execution result of the above program is 1
.
Recommended reading
Generics
Fuzzing
Workspace Mode
open source address
Articles and sample code are open sourced on GitHub: Beginner, Intermediate, and Advanced Tutorials in Go .
Official account: coding advanced. Follow the official account to get the latest Go interview questions and technology stacks.
Personal website: Jincheng's Blog .
Zhihu: Wuji
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。