diff options
| author | Ian Lance Taylor <iant@golang.org> | 2020-06-21 20:54:13 -0700 |
|---|---|---|
| committer | Ian Lance Taylor <iant@golang.org> | 2020-06-22 22:40:22 +0000 |
| commit | d60d27c80e1dbedf58cfdaa482c6d30801f05139 (patch) | |
| tree | 99d5f6a60e8775f55aa72cd35cb9aa22965a422d | |
| parent | 53c98a495b13642423f9403909e9c6e4d9104c15 (diff) | |
| download | go-x-proposal-d60d27c80e1dbedf58cfdaa482c6d30801f05139.tar.xz | |
design/go2draft-type-parameters: add parameterized methods notes
Change-Id: I1527928f5fd6550e366faa88527e7281483b3846
Reviewed-on: https://go-review.googlesource.com/c/proposal/+/239169
Reviewed-by: Robert Griesemer <gri@golang.org>
| -rw-r--r-- | design/go2draft-type-parameters.md | 102 |
1 files changed, 97 insertions, 5 deletions
diff --git a/design/go2draft-type-parameters.md b/design/go2draft-type-parameters.md index 65e42b8..d765710 100644 --- a/design/go2draft-type-parameters.md +++ b/design/go2draft-type-parameters.md @@ -554,11 +554,8 @@ methods may not themselves have additional type parameters. Where it would be useful to add type arguments to a method, people will have to write a suitably parameterized top-level function. -This is not a fundamental restriction but it complicates the language -specification and the implementation. - -(Note: this is a feature that can perhaps be added later if it proves -necessary.) +There is more discussion of this in [the issues +section](#No-parameterized-methods). ### Operators @@ -2158,6 +2155,101 @@ func Copy(type T1, T2)(dst []T1, src []T2) int { } ``` +##### No parameterized methods + +This design draft does not permit methods to declare type parameters +that are specific to the method. +The receiver may have type parameters, but the method not add any type +parameters. + +In Go, one of the main roles of methods is to permit types to +implement interfaces. +It is not clear whether it is reasonably possible to permit +parameterized methods to implement interfaces. +For example, consider this code, which uses the obvious syntax for +parameterized methods. +This code uses multiple packages to make the problem clearer. + +```Go +package p1 + +// S is a type with a parameterized method M. +type S struct{} + +// Identity is a simple identity method that works for any type. +func (S) Identity(type T)(v T) T { return v } + +package p2 + +// HasIdentity is an interface that matches any type with a +// parameterized Identity method. +type HasIdentity interface { + Identity(type T)(T) T +} + +package p3 + +import "p2" + +// CheckIdentity checks the Identity method if it exists. +// Note that although this function calls a parameterized method, +// this function is not itself parameterized. +func CheckIdentity(v interface{}) { + if vi, ok := v.(p2.HasIdentity); ok { + if got := vi.Identity(int)(0); got != 0 { + panic(got) + } + } +} + +package p4 + +import ( + "p1" + "p3" +) + +// CheckSIdentity passes an S value to CheckIdentity. +func CheckSIdentity() { + p3.CheckIdentity(p1.S{}) +} +``` + +In this example, we have a type `S` with a parameterized method and a +type `HasIdentity` that also has a parameterized method. +`S` implements `HasIdentity`. +Therefore, the function `p3.CheckIdentity` can call `vi.Identity` with +an `int` argument, which in this example will be a call to +`S.Identity(int)`. +But package p3 does not know anything about the type `p1.S`. +There may be no other call to `S.Identity` elsewhere in the program. +We need to instantiate `S.Identity(int)` somewhere, but how? + +We could instantiate it at link time, but in the general case that +requires the linker to traverse the complete call graph of the program +to determine the set of types that might be passed to `CheckIdentity`. +And even that traversal is not sufficient in the general case when +type reflection gets involved, as reflection might look up methods +based on strings input by the user. +So in general instantiating parameterized methods in the linker might +require instantiating every parameterized method for every possible +type argument, which seems untenable. + +Or, we could instantiate it run time. +In general this means using some sort of JIT, or compiling the code to +use some sort of reflection based approach. +Either approach would be very complex to implement, and would be +surprisingly slow at run time. + +Or, we could decide that parameterized methods do not, in fact, +implement interfaces, but then it's much less clear why we need +methods at all. +If we disregard interfaces, any parameterized method can be +implemented as a parameterized function. + +So while parameterized methods seem clearly useful at first glance, we +would have to decide what they mean and how to implement that. + #### Discarded ideas This design is not perfect, and it will be further refined as we gain |
