3

I'm trying to implement the interface Interface using generics. It has one method which accepts another Interface as a parameter:

type SubInterface interface {
    SendResponse(string)
}

type Interface interface {
    Subscribe(SubInterface)
}

I've come up with the following generic version of those interfaces:

type GenericSubInterface[T any] interface {
    SendResponse(T)
}

type GenericInterface[Res any] interface {
    Subscribe(GenericSubInterface[Res])
}

I would expect GenericInterface[string] to be assignable to Interface but it somehow isn't.

var a Interface
var b GenericInterface[string]

//  cannot use b (variable of type GenericInterface[string]) as Interface value in assignment: GenericInterface[string] does not implement Interface (wrong type for method Subscribe)
//      have Subscribe(GenericSubInterface[string])
//      want Subscribe(SubInterface)
a = b

Creating a generic implementation of Interface doesn't work either:

type GenericImplementation[Res any] struct {
}

func (i *GenericImplementation[Res])Subscribe(ss GenericSubInterface[Res]) {
    var msg Res
    ss.SendResponse(msg)
}
//  cannot use &GenericImplementation[string]{} (value of type *GenericImplementation[string]) as Interface value in variable declaration: *GenericImplementation[string] does not implement Interface (wrong type for method Subscribe)
//      have Subscribe(GenericSubInterface[string])
//      want Subscribe(SubInterface)
var c Interface = &GenericImplementation[string]{}

What seems weird to me is that the sub-interfaces are assignable to each other:

var d SubInterface
var e GenericSubInterface[string]

// works fine
d = e

The problem only seems to occur when interfaces are nested somehow. Is there any way around this that I can implement Interface using generics for types other than string?

Full playground example

0

2 Answers 2

3

First, read Go interface: interface not implemented even though it is. The very first sentence of @colm.anseo's answer already summarizes the issue:

The signatures are not the same. The argument types are different

Then read How to implement generic interfaces?. Values of type SubInterface are assignable to a particular instantiation of GenericSubInterface, namely GenericSubInterface[string], because the methods end up being identical — SendResponse(string).

Interface is not assignable to GenericInterface[string] because the methods end up being not identical. The error message is as eloquent as it gets:

have Subscribe(GenericSubInterface[string])
want Subscribe(SubInterface)

You can use the generic version of your interfaces, however the methods must be implemented exactly. So you have to make the function AcceptInterface generic too:

func AcceptInterface[T any](a GenericInterface[T]) {
}

func main() {
    var b GenericInterface[string]
    AcceptInterface(b)
}
Sign up to request clarification or add additional context in comments.

2 Comments

I see, I've misinterpreted this as an issue with generics when actually it isn't. If func AcceptInterface(a Interface) is not under my control, there's no way to pass it a generic implementation?
You can pass a generic implementation only if the implementor has the same method signatures after instantiation
1

I've found a solution to satisfy Interface using generics that fits my use case. Any nested interface has to be specified as an additional type parameter. This makes the instantiation a little more verbose but allows for GenericInterface and GenericImplementation to satisfy Interface:

// Interface

type GenericInterface[Res any, Arg GenericSubInterface[Res]] interface {
    Subscribe(Arg)
}

var a Interface
var b GenericInterface[string, SubInterface]
a = b // works

// Implementation

type GenericImplementation[Res any, Arg GenericSubInterface[Res]] struct {
}

func (i *GenericImplementation[Res, Arg]) Subscribe(ss Arg) {
    var msg Res
    ss.SendResponse(msg)
}

var c Interface = &GenericImplementation[string, SubInterface]{} // works

1 Comment

just don't forget that GenericInterface[string, SubInterface] is the only instantiation that is assignable to Interface

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.