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: allow eliding "_" fields in unkeyed struct literals #71458

Open
dr2chase opened this issue Jan 27, 2025 · 4 comments
Open

proposal: allow eliding "_" fields in unkeyed struct literals #71458

dr2chase opened this issue Jan 27, 2025 · 4 comments
Labels
LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee LanguageProposal Issues describing a requested change to the Go language specification. Proposal
Milestone

Comments

@dr2chase
Copy link
Contributor

Proposal Details

Change treatment of _ fields so that they may be omitted from unkeyed struct literals and (if omitted) do not count as unexported fields. In the case of a struct with multiple _ fields, either all must be present or all must be omitted, to avoid ambiguity.

The reason for this is to make it easier to use _ fields for things like establishing field alignment, modifying layout, and other type attributes. Without this change, _ fields require providing pointless initial "values" in unkeyed literals, and make it impossible to use unkeyed literals across package boundaries (it may be bad style, but it is legal Go and probably exists -- a particular use case is Windows). One specific motivation was looking at the work required and effects on code/tools/usability to add structs.HostLayout annotations to the code generated by cgo; it was messy and unpleasant.

This breaks no Go code, so it is compatible.

It also "potentially affects" very little code anyway; unkeyed literals for structs with _ fields are rare. I ran an ecosystem analysis of 44,000 Go projects that were imported 5 or more times. Of those, there were only 137 instances of an unkeyed literal "initializing" a _ field. Of that 137, 127 were in tests, of of that 127, 75 were literals for the same struct type. Of the 10 "non-test" examples, it turned out to really be only 5 because of duplication in the report, appearing in only 3 p[rojects, and 2 of that 3 involved VNC (i.e., derivative code).

In any case where the export-forbidding properties of _ were desirable, renaming that field to any other export-forbidding name (e.g., __ or underscore) obtains the same effect.

This will require a change to the Go compiler, and to tools that analyze Go code, so that both forms of struct literals are recognized.

@gopherbot gopherbot added this to the Proposal milestone Jan 27, 2025
@ianlancetaylor ianlancetaylor added LanguageChange Suggested changes to the Go language LanguageChangeReview Discussed by language change review committee labels Jan 27, 2025
@ianlancetaylor
Copy link
Member

For example, given

type S struct {
    F1 bool
    _   int
    F2 bool
}

code would be permitted to write

var s = S{true, false}

Currently that is not permitted. With this proposal, it would be permitted. In particular, since F1 and F2 are exported, it would be permitted in a different package.

Let me know if that is not right.

@timothy-king
Copy link
Contributor

One specific motivation was looking at the work required and effects on code/tools/usability to add structs.HostLayout annotations to the code generated by cgo; it was messy and unpleasant.

More details on what "messy and unpleasant" looked like in practice would be helpful here. I don't think I understand the motivation yet.

@gabyhelp gabyhelp added the LanguageProposal Issues describing a requested change to the Go language specification. label Jan 27, 2025
@rittneje
Copy link

In any case where the export-forbidding properties of _ were desirable, renaming that field to any other export-forbidding name (e.g., __ or underscore) obtains the same effect.

While perhaps not literally a breaking change, this feels like a breaking change in spirit.

@dr2chase
Copy link
Contributor Author

@timothy-king It was messy in its interactions with gopls, and there were spurious (false positive) errors. I do not recall the exact details, but it caused me to abandon work on that change to cgo.

The motivation is that we think these annotations should be added to platform specific code, but anytime that an API exports a platform data structure, it will force what is effectively a breaking change to their API. I.e., the annotation creates a problem, and I would prefer that it not create a problem.

Allowing these annotations gives us a way to note when a structure's layout matters, and therefore also when it does not matter, so that the compiler can do a better job of arranging structures for both size and pointer locality (which affects the memory bandwidth requirements of GC in some cases). That would let us remove a by-hand optimization task, and remove a constraint of field-ordering (which in theory means that programmers can arrange them more "naturally", whatever that might mean).

There have been other proposals for things we might do with zero-sized annotation fields, some of them are probably worthwhile, and letting _ fields be ignored in this way will reduce the barrier to use of such fields whenever they might appear in a public API.

The reason for using zero-sized annotation fields (in general) is that when such types cannot be mixed (because of layout changes, or use restrictions, or whatever annotations we come up with), the presence of differing fields acts through the existing type system to keep them separate; this approach causes less breakage/surprise in the Go tools, than, say, adding a magic //go:whatever annotation to a type.

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 LanguageProposal Issues describing a requested change to the Go language specification. Proposal
Projects
None yet
Development

No branches or pull requests

6 participants