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

reflect: NumMethod includes non-exported methods for interface types #22075

Open
mdempsky opened this Issue Sep 28, 2017 · 10 comments

Comments

Projects
None yet
5 participants
@mdempsky
Member

mdempsky commented Sep 28, 2017

Type.Method's docs say:

NumMethod returns the number of exported methods in the type's method set.

Value.Method's docs say:

NumMethod returns the number of exported methods in the value's method set.

But this program demonstrates that they both include the number of non-exported methods when applied to interface types: https://play.golang.org/p/Drv0u6n9bg

According to the documentation, it should print "0 0", but instead it prints "1 1".

/cc @ianlancetaylor @crawshaw

Related #22073.

@mdempsky

This comment has been minimized.

Member

mdempsky commented Sep 28, 2017

Incidentally, if we fix this such that you can only access exported methods (as appears to be the intent), reflect.Method's PkgPath field becomes unnecessary (it will always be ""). However, we can't remove it until Go 2.

@mvdan mvdan self-assigned this Feb 19, 2018

@mvdan

This comment has been minimized.

Member

mvdan commented Feb 20, 2018

@mdempsky I see multiple potential solutions:

  • Use rtype for its exportedMethods method (although I presume this is not an option, sine interfaces currently handle methods on their own - is there a good reason to keep the code split in two?)
  • Add an exportedMethods method to interfaceType, with caching similar to methodCache
  • Add an exportedMethods field to interfaceType, statically containing the subset of exported methods
@mvdan

This comment has been minimized.

Member

mvdan commented Mar 15, 2018

Ping, @mdempsky?

@mdempsky mdempsky added this to the Go1.11 milestone Mar 15, 2018

@mdempsky

This comment has been minimized.

Member

mdempsky commented Mar 15, 2018

@mvdan Assuming the NumMethods documentation is correct and the implementation is just wrong for interfaces, then those solutions sound reasonable.

I wanted some of the reflect API experts to weigh in first on whether the code needs to be fixed, or the document just needs to be updated.

@mvdan

This comment has been minimized.

Member

mvdan commented Mar 15, 2018

Gotcha - unassigning self for now. I thought this didn't need a decision.

@mvdan mvdan removed their assignment Mar 15, 2018

@mdempsky

This comment has been minimized.

Member

mdempsky commented Mar 15, 2018

@mvdan For what it's worth, my 2c is we should fix the code to match the current documentation. The main hesitation in my mind is just whether users are inadvertently relying on the current behavior.

If you want to speculatively work on a fix, that might also help answer the question of whether users depend on the current behavior or not.

As for recommended fix, I'm not sure we need methodCache at all. I would think the compiler could sort all exported methods before nonexported methods, and then we can add a xcount field next to mcount to indicate how many methods are exported. I think as long as we sort concrete and interface methods the same way, the "Implements" algorithm should still work fine. (I feel like I've described this in an issue or during a CL review before, but can't find it off hand.)

I think uncommontype and interfacetype will need to keep separate exportedMethods code, because the former returns []method (i.e., concrete methods), while the latter returns []imethod (i.e., interface methods). However, if we eliminate methodCache, I think the code duplication will go down substantially.

@gopherbot

This comment has been minimized.

gopherbot commented Mar 15, 2018

Change https://golang.org/cl/100846 mentions this issue: reflect: sort exported methods first

@gopherbot

This comment has been minimized.

gopherbot commented Mar 15, 2018

Change https://golang.org/cl/100845 mentions this issue: cmd/compile: sort method sets earlier

@mdempsky

This comment has been minimized.

Member

mdempsky commented Mar 15, 2018

CL 100846 above gets rid of methodCache. It should be much easier to build on to fix NumMethod for interface types.

gopherbot pushed a commit that referenced this issue Mar 15, 2018

cmd/compile: sort method sets earlier
By sorting method sets earlier, we can change the interface
satisfaction problem from taking O(NM) time to O(N+M). This is the
same algorithm already used by runtime and reflect for dynamic
interface satisfaction testing.

For #22075.

Change-Id: I3d889f0227f37704535739bbde11f5107b4eea17
Reviewed-on: https://go-review.googlesource.com/100845
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>

gopherbot pushed a commit that referenced this issue Mar 15, 2018

reflect: sort exported methods first
By moving exported methods to the front of method lists, filtering
down to only the exported methods just needs a count of how many
exported methods exist, which the compiler can statically
provide. This allows getting rid of the exported method cache.

For #22075.

Change-Id: I8eeb274563a2940e1347c34d673f843ae2569064
Reviewed-on: https://go-review.googlesource.com/100846
Reviewed-by: Ian Lance Taylor <iant@golang.org>

@ianlancetaylor ianlancetaylor modified the milestones: Go1.11, Go1.12 Jun 27, 2018

dmitshur added a commit to gopherjs/gopherjs that referenced this issue Jun 29, 2018

natives/reflect: Sort exported methods first; add xcount to uncommonT…
…ype.

What was previously an unused blank identifier field of type uint16 in
Go 1.10 has become the xcount field in Go 1.11. Update our uncommonType
to match.

Also remove the unused uint32 field at the end. In normal Go, it's used
for padding and to keep the struct size fixed size. GopherJS doesn't
need that, because it doesn't support unsafe memory operations.

Fixes:

	$ gopherjs build reflect
	reflect/type.go:2603:5: invalid operation: ut (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:643:7: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:88: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:97: invalid operation: t (variable of type *uncommonType) has no field or method xcount

Follows golang/go@86a3389.
Updates golang/go#22075.

dmitshur added a commit to gopherjs/gopherjs that referenced this issue Jun 29, 2018

natives/reflect: Sort exported methods first; add xcount to uncommonT…
…ype.

What was previously an unused blank identifier field of type uint16 in
Go 1.10 has become the xcount field in Go 1.11. Update our uncommonType
to match.

Also remove the unused uint32 field at the end. In normal Go, it's used
for padding and to keep the struct size fixed size. GopherJS doesn't
need that, because it doesn't support unsafe memory operations.

Fixes:

	$ gopherjs build reflect
	reflect/type.go:2603:5: invalid operation: ut (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:643:7: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:88: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:97: invalid operation: t (variable of type *uncommonType) has no field or method xcount

Follows golang/go@86a3389.
Updates golang/go#22075.

dmitshur added a commit to gopherjs/gopherjs that referenced this issue Jun 29, 2018

natives/reflect: Sort exported methods first; add xcount to uncommonT…
…ype.

What was previously an unused blank identifier field of type uint16 in
Go 1.10 has become the xcount field in Go 1.11. Update our uncommonType
to match.

Also remove the unused uint32 field at the end. In normal Go, it's used
for padding and to keep the struct size fixed size. GopherJS doesn't
need that, because it doesn't support unsafe memory operations.

Fixes:

	$ gopherjs build reflect
	reflect/type.go:2603:5: invalid operation: ut (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:643:7: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:88: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:97: invalid operation: t (variable of type *uncommonType) has no field or method xcount

Follows golang/go@86a3389.
Updates golang/go#22075.

dmitshur added a commit to gopherjs/gopherjs that referenced this issue Aug 21, 2018

natives/reflect: Sort exported methods first; add xcount to uncommonT…
…ype.

What was previously an unused blank identifier field of type uint16 in
Go 1.10 has become the xcount field in Go 1.11. Update our uncommonType
to match.

Also remove the unused uint32 field at the end. In normal Go, it's used
for padding and to keep the struct size fixed size. GopherJS doesn't
need that, because it doesn't support unsafe memory operations.

Fixes:

	$ gopherjs build reflect
	reflect/type.go:2603:5: invalid operation: ut (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:643:7: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:88: invalid operation: t (variable of type *uncommonType) has no field or method xcount
	reflect/type.go:646:97: invalid operation: t (variable of type *uncommonType) has no field or method xcount

Follows golang/go@86a3389.
Updates golang/go#22075.
@rsc

This comment has been minimized.

Contributor

rsc commented Nov 14, 2018

Let's do this early in Go 1.13. I'm scared of changing it now but it seems like a reasonable change.

@rsc rsc modified the milestones: Go1.12, Go1.13 Nov 14, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment