Background: Within x/tools alone, the pattern of a loop over the objects in a types.Scope appears at least 29 times:
tools$ ag -A1 'for _, name := range .*[Ss]cope.*Names\(\) {'
cmd/godex/print.go
88: for _, name := range scope.Names() {
89- obj := scope.Lookup(name)
cmd/bundle/main.go
224: for _, name := range scope.Names() {
225- rename(scope.Lookup(name))
cmd/deadcode/deadcode.go
186: for _, name := range scope.Names() {
187- if typeName, ok := scope.Lookup(name).(*types.TypeName); ok &&
go/gcexportdata/main.go
84: for _, name := range scope.Names() {
85- obj := scope.Lookup(name)
...24 more...
With an iterator, this would be simplified to:
for obj := range scope.Elements() { ... }
Proposal: We propose to add the Elements method to Scope to provide an iterator over the objects:
package types // "go/types"
// Elements returns an iterator over the objects in the s in name order.
//
// Example: for obj := range scope.Elements() { ... }
func (s *Scope) Elements() iter.Seq[Object] {
// TODO(adonovan): opt: names allocates and sorts,
// which has been a performance problem for clients
// in the past. Perhaps this iterator should leave
// the order unspecified?
names := s.Names()
return func(yield func(obj Object) bool) {
for _, name := range names {
if !yield(s.Lookup(name)) {
break
}
}
}
}
I think the likely answer to the question in the TODO is "no", but performance is a concern. Perhaps a better approach would be for Scope to amortize the construction of the sorted Names array by retaining it after first use (using a sync.Once or similar).
@griesemer @mrkfrmn
Background: Within x/tools alone, the pattern of a loop over the objects in a types.Scope appears at least 29 times:
With an iterator, this would be simplified to:
Proposal: We propose to add the Elements method to Scope to provide an iterator over the objects:
I think the likely answer to the question in the TODO is "no", but performance is a concern. Perhaps a better approach would be for Scope to amortize the construction of the sorted Names array by retaining it after first use (using a sync.Once or similar).
@griesemer @mrkfrmn