Skip to content
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

spec: potential ambiguity in package initialization #70571

Closed
TutiFrouti opened this issue Nov 26, 2024 · 7 comments
Closed

spec: potential ambiguity in package initialization #70571

TutiFrouti opened this issue Nov 26, 2024 · 7 comments
Labels
Documentation Issues describing a change to documentation.

Comments

@TutiFrouti
Copy link

What is the URL of the page with the issue?

https://go.dev/ref/spec#Package_initialization

What is your user agent?

Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36

Screenshot

image

What did you do?

Does the variable c depends on the variables a and b in the following program?

package main

import "fmt"

var a = 10
var b = 20
var c = func() int {
	return a + b
}()

func main() {
	fmt.Println(a, b, c)
}

In my understanding of the specification (package initialization), we have the following references:

  1. a reference to the variable is an identifier to that variable - 1. rule
  2. a reference to the function is an identifier to that function (it doesn't matter if it's invoked) - 1. rule
  3. a reference to the method is a selector t.m where t is non-interface type (it doesn't matter if it's invoked) - 2. rule

Additionally, spec says - 3. rule:

A variable, function, or method x depends on a variable y if x's initialization expression or body (for functions and methods) contains a reference to y or to a function or method that depends on y.

Back to my example. It is clear that "anonymous" function depends on the a and b, but does c depend on the a and b? Spec says that c's initialization expression must contain reference to the function that depends on the a and b and my understanding is that this reference to the function (according to the 1. rule) is only by identifier, but not by "anonymous" function / function literal. Therefore, the reference to the function is defined by the 1st rule (same as the reference to the method is defined by the 2. rule).

For me, this case is unspecified (same as with methods on interfaces).

However, when I print c it gives 30 (it's okay to me, since it is unspecified; it can also be 0, 10, 20). Also, my colleagues and AI tools say that the dependency also holds in this case...

Who is right, what is true?

What did you see happen?

I see that the result of the variable c is 30, but I'm not sure if this is "random" (since it is not specified) or the spec guarantees it even for the anonymous functions / function literals.

What did you expect to see?

Resolving potential ambiguity. If I'm right, it would be great to potentially add an example with a function literal (as was done for interfaces and methods).

@rittneje
Copy link

As per the spec, the FunctionLit in your example is part of a PrimaryExpr representing the function call, which in turn is the Expression for the declaration of c. Consequently, the entire body of your anonymous function is part of c's initialization expression, and by extension c's initialization expression contains a reference to both a and b.

@adonovan adonovan added Documentation Issues describing a change to documentation. and removed pkgsite labels Nov 26, 2024
@TutiFrouti
Copy link
Author

@rittneje The 3. rule specifies that the initialization expression must contain a reference to a function. The 1. rule defines such a reference as only an identifier.

Similarly, the 2. rule defines reference to method. So, even though the 3. rule does not explicitly state anything about interfaces, we can infer from the 2. rule that in an expression t.m, t cannot be an interface.

@rittneje
Copy link

@TutiFrouti It is not true that the initialization expression must contain a reference to a function. For example, var c = a + b is perfectly legal.

In your case, the whole initialization expression is func() int { return a + b }(). That is the, the function literal itself is part of the initialization expression. Since the expression references a and b, that means that c depends on a and b.

@TutiFrouti
Copy link
Author

TutiFrouti commented Nov 26, 2024

@rittneje I didn't say that the initialization expression must contain a reference to a function. I said that if it contains, according to the spec, that must be an identifier in order to establish the dependency.

Spec (I bolded myself):

  • A reference to a variable or function is an identifier denoting that variable or function.
  • A variable, function, or method x depends on a variable y if x's initialization expression or body (for functions and methods) contains a reference to y or to a function or method that depends on y.

@rittneje
Copy link

Omitting the parts not relevant to this conversation, the spec says:

A variable [...] x depends on a variable y if x's initialization expression [...] contains a reference to y.

For an anonymous func, the function's body is considered part of the expression, as per the spec. So it is by this spec point that we can conclude that c's initialization expression contains a reference to both a and b. And thus c depends on a and b.

@seankhliao
Copy link
Member

see above.

@seankhliao seankhliao closed this as not planned Won't fix, can't repro, duplicate, stale Nov 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Documentation Issues describing a change to documentation.
Projects
None yet
Development

No branches or pull requests

5 participants