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

proposal: spec: file and package scope interact in odd ways #7429

Open
griesemer opened this issue Feb 27, 2014 · 7 comments
Open

proposal: spec: file and package scope interact in odd ways #7429

griesemer opened this issue Feb 27, 2014 · 7 comments
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal
Milestone

Comments

@griesemer
Copy link
Contributor

This is just a reminder to revisit the interactions between file and package scope at
some point in the future.

At the moment we have the following rule:

"... no identifier may be declared in both the file and package block." (
http://tip.golang.org/ref/spec#Declarations_and_scope )

The reason for this rule is that we don't want to, say, import package math, and also
have a - in the same file - a package level variable math, and the import would then
hide the variable because the file block is inside the package block, and not have any
visible nesting (in fact the nesting is "inside out" in this case).

However, as a consequence, other odd behavior follows. Assume a package p consisting of
two files a.go, b.go, with a.go importing package math, and b.go not importing anything.

In b.go, the identifier math is not visible (it is in a.go's file scope), yet it is not
possible to declare a package-level variable math in b.go w/o an error because of the
above-cited rule. This is counter-intuitive.

One could imagine an alternative approach that satisfies the same intent, namely avoids
that both an import of an identifier x hides a package-level identifier x in the same
file:

- File blocks are nested inside the package block as before.
- Each import and also each top-level declaration in a file go into the file block.
- Additionally, each non-imported identifier also goes into the package block.

This way, all non-imported top-level identifiers are visible in all files. Imports
remain only visible in the file containing the import. Imports and file-level
declarations cannot conflict (this is the main purpose of the above rule).

Implementation-wise there may be different approaches to obtain the desired behavior. A
direct implementation of these new rules might lead to the (possibly undesired) property
that non-import file-level declarations end up both in a compiler's file and package
scope, that is, an object belongs to two scopes simultaneously.

The new rules would be a backward-compatible language change.
@cznic
Copy link
Contributor

cznic commented Feb 28, 2014

Comment 1:

Also, not allowing to shadow the imported package qualifier is somewhat inconsistently
enforced only for TLDs: http://play.golang.org/p/77zRRbFxdI
Relaxing the current rules to allow a TLD named x in a file which doesn't use x as an
import qualifier even when some other file of the same package does would be IMHO an
improvement. The existing rule can eg. make some trouble when moving code between
packages, though probably not often.
Perhaps: "... no identifier may be declared in both the file and package block from
within the same source file"?

@griesemer
Copy link
Contributor Author

Comment 2:

Labels changed: added repo-main.

@griesemer griesemer added longterm LanguageChange Suggested changes to the Go language labels Apr 21, 2014
@griesemer griesemer self-assigned this Apr 21, 2014
@rsc rsc added this to the Unplanned milestone Apr 10, 2015
@zigo101
Copy link

zigo101 commented Feb 25, 2017

no identifier may be declared in both the file and package block.

Why this? Any bad to make top level identifiers declared in both file and package blocks?
Just like the explanation in this article: http://www.tapirgames.com/blog/golang-block-and-scope ?
By thinking like this, it is consistent and easy to explain identifier shadowing.

@zigo101
Copy link

zigo101 commented Feb 25, 2017

A direct implementation of these new rules might lead to the (possibly undesired) property
that non-import file-level declarations end up both in a compiler's file and package
scope, that is, an object belongs to two scopes simultaneously.

Aha, this is the same as the article mentioned above. I think this is a better approach.

The new rules would be a backward-compatible language change.

Need changes in go/* packages?

@rsc rsc changed the title spec: file and package scope interact in odd ways proposal: spec: file and package scope interact in odd ways Jun 20, 2017
@rsc rsc added the v2 An incompatible library change label Jun 20, 2017
@ianlancetaylor ianlancetaylor added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Dec 13, 2017
@gopherbot gopherbot removed the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Aug 16, 2019
@gopherbot gopherbot added the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label Sep 3, 2019
@bradfitz
Copy link
Contributor

Playground link with demo: https://play.golang.org/p/ujhxUDdvktn

@ianlancetaylor ianlancetaylor modified the milestones: Unplanned, Proposal May 12, 2020
@ianlancetaylor ianlancetaylor removed the NeedsDecision Feedback is required from experts, contributors, and/or the community before a change can be made. label May 12, 2020
@griesemer
Copy link
Contributor Author

The situation is exacerbated with dot-imports: A dot-import in one file will "pollute" the package-level namespace as no name that is dot-imported can be used in any other file of the same package. With this proposal, this pollution wouldn't matter because file scopes shadow the package scope.

@smasher164
Copy link
Member

smasher164 commented Jul 16, 2023

A direct implementation of these new rules might lead to the (possibly undesired) property
that non-import file-level declarations end up both in a compiler's file and package
scope, that is, an object belongs to two scopes simultaneously.

I think as long as you have the ability to track the file from which any non-imported top-level identifier came, you can keep their scopes disjoint. So for any imported identifier that is introduced, you do a recursive lookup. If the lookup succeeds, then you check that it's from the same file. If it is, then that's an error. Otherwise, the imported identifier shadows.

Note that this allows you to keep top-level declarations inside package scope, and imports in file scope -- disjoint from each other.

@ianlancetaylor ianlancetaylor added Proposal and removed v2 An incompatible library change labels Aug 6, 2024
@ianlancetaylor ianlancetaylor added the LanguageChangeReview Discussed by language change review committee label Aug 6, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee Proposal
Projects
None yet
Development

No branches or pull requests

8 participants