*Axel Wagner*, I've "read" the thread you linked (read some posts and
skimmed through others) and also read the following article (which I
should've read sooner):
https://research.swtch.com/interfaces
and now I understand the issue a little bit better (hopefully). As a result
I have the only suggestion left for now in regards to generic methods:
1. For an interface's generic methods disallow the use of "any" constraint
for type parameters.
type HasIdentity interface {
Identity[T int64 | float64](T) T // ok
// Identifoo[T any](T) T // not allowed
}
2. For a type's generic methods there should be no restrictions for
constraints.
type Foo struct {...}
func (foo Foo) Identity[T any](v T) T { return v } // ok
3. Generic methods that are invoked on variables of concrete types should
behave just like regular generic functions.
foo := Foo{}
v := foo.Identity(123) // the same as calling Identity[T any](foo Foo, v T)
T with T = int and the same body as the method
4. Types' generic methods should only be able to satisfy interfaces'
generic methods. Types' non-generic methods should only be able to satisfy
interfaces' non-generic methods.
5. When the whole program code is analyzed by the compiler we should know
exactly which types satisfy which interfaces and which types satisfy which
*constraints*. So...
5a. Every generic method in every interface should be turned into several
non-generic methods with their type parameters substituted for every
possible concrete types according to their constraints. For the HasIdentity
example above we'll have:
type HasIdentity interface {
Identity[int64](int64) int64
Identity[float64](float64) float64
}
5b. For every type that has generic methods and that satisfies some
interface the corresponding constraints from the interfaces' generic method
type parameters should be used to generate all possible method variations
for this type. So for the Foo struct above we know that according to its
generic Identity method signature it should satisfy the interface
HasIdentity so we take the corresponding type parameter constraint from
HasIdentity's method (int64 | float64) and use it to generate the needed
methods:
type Foo struct{}
func (foo Foo) Identity[int64](v int64) int64 { return v }
func (foo Foo) Identity[float64](v float64) float64 { return v }
So the usage can be:
var a any = Foo{}
// the HasIdentity method table has 2 entries
// which map to the corresponding 2 entries in the Foo method table
h := a.(HasIdentity)
i := h.Identity(123)
f := h.Identity(1.0)
Hopefully I conveyed the main idea. Looking forward to a feedback.
On Tuesday, October 29, 2024 at 10:22:36 AM UTC+3 Axel Wagner wrote:
> From an off-list response:
>
> 1. It only works if the function is defined in the same package as its
>>> used, or you'd need to use dot-imports.
>>
>> The dot-import in this case seems redundant because we have a variable
>> with which we try to use a method syntax and this variable has a specific
>> type and this type was defined in a specific package and all of this is
>> known at compile time. So can't the compiler just perform a check along the
>> lines of "if we use the method call syntax on this variable and if the type
>> of this variable is not an interface and if there's no method with the
>> required signature then check if there's a regular function with the
>> required signature defined in the same package as the type of the variable"?
>>
>
> What you are describing here are effectively methods. You are just saying
> that, in addition to a method being declared as "func (T) M()`, it can also
> be declared as `func M(T)`. But nothing changes about the fundamental
> association between the body and the type, that characterizes a method. So
> it comes with exactly the same downsides as regular methods, with the added
> downside that we now have two different kinds of methods, that behave
> subtly differently (in that only one kind participates in interface
> implementation). It also means that a package can not define the generic
> `Map` method people seem to want on more than one type. Which, again, is
> unlikely to be what people want.
>
> I really encourage you to read #49085
> <https://github.com/golang/go/issues/49085>, if you find the FAQ entry
> unsatisfactory. It contains a lot of additional discussion and in
> particular this suggestion and probably every variation of it you can think
> of has been discussed there already.
>
--
You received this message because you are subscribed to the Google Groups
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion visit
https://groups.google.com/d/msgid/golang-nuts/616b3f30-f463-4f95-ad84-b3fd6a39ed87n%40googlegroups.com.