New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
cmd/compile: top-level var does not respect , rule #7320
Comments
Yes, r or gri reported the same thing last week I think, but I cannot find that one. The issue is that the compiler treats all top-level variables as separate for the purposes of computing an order, and so the "a before b" you are relying on is not there in the compiler. However, it is also unclear to me whether it is really there in practice. What about: var a, b = f(), g() func f() int { return b } func g() int { return 5 } Today the compiler just initializes b - which means calling g - before calling f, as it must. We could make this an init loop error, and perhaps we should, but I think that's a language change at this point. If I remember correctly, the earlier report (which I also cannot find) contained a similar example. There's a spec question here before there's a compiler bug. It would be nice to answer the spec question at least before Go 1.3. Labels changed: added release-go1.3. Status changed to Accepted. |
I think the spec on this point is actually complete and unambiguous, if a little hard to read. "Within a package, package-level variables are initialized, and constant values are determined, according to order of reference: if the initializer of A depends on B, A will be set after B. Dependency analysis does not depend on the actual values of the items being initialized, only on their appearance in the source. A depends on B if the value of A contains a mention of B, contains a value whose initializer mentions B, or mentions a function that mentions B, recursively. It is an error if such dependencies form a cycle. If two items are not interdependent, they will be initialized in the order they appear in the source, possibly in multiple files, as presented to the compiler." (The word "mention" needs a proper definition, but its meaning is clear enough as it relates to this issue.) I think the compiler is correct to treat var x, y = f(), g() as equivalent to var x = f(); var y = g(), i.e. all 1:1 initializations of top-level vars should be treated as if declared separately. (NB: var x, y = z() is quite different.) In your example, the init graph contains these edges: a->f->b->g which already gives us a total order. This is a degenerate case since there are no incomparable pairs, so we don't even need to look at the lexical order of declaration. Does anyone really think this should be an error? |
Yes, that's right. For the record, I found the other bug you mentioned: "evaluation order and initialization order specs are in contradiction" https://golang.org/issue/7137 I don't have an opinion on that one, other than that the spec and implementations be made to agree. |
Issue #7134 has been merged into this issue. |
Better simpler program: package main var order = [2]int{b, a} var a, b = next(), next() // 0, 1 func main() { if a != 0 || b != 1 { println(a, b) panic("order") } } var counter int func next() int { c := counter counter++ return c } Not going to fix this for Go 1.3. It's too subtle and too unimportant. Labels changed: added release-go1.4, removed release-go1.3. |
Thank you for the report, and for the patience @alandonovan, and thank you for the discussion and attention @rsc and @griesemer! I have just investigated this issue and good news: This bug was fixed for Go1.13 by @mdempsky's CL 170062 after an identical bug #22326 was filed calling out a mismatch with the spec's expectations in an example. I am going to close this bug as it is now fixed. Thank you all! |
The text was updated successfully, but these errors were encountered: