komatsu
komatsu

Reputation: 83

How to use an interface in a callback with Golang?

I am trying to use a Faye client for Go but when I try to make an interface for the client it seems to fail due to to the type in the callback:

package main

import (
    "fmt"
    "github.com/autogrowsystems/wray"
)

type Message interface {
    Data() map[string]interface{}
}

type Promise interface {
    Successful() bool
}

type Subscriber interface {
    Subscribe(string, bool, func(Message)) (Promise, error)
}

func subscribeMe(subber Subscriber) {
    subber.Subscribe("/my/chan", false, func(msg Message) {
        fmt.Printf("got data: %+v", msg.Data())
    })
}

func main() {
    subscribeMe(wray.NewFayeClient("http://localhost/faye"))
    fmt.Println("all good!")
}

At that point it fails with the following error:

# command-line-arguments
main/fayetest.go:27: cannot use wray.NewFayeClient("http://localhost/faye") (type *wray.FayeClient) as type Subscriber in argument to subscribeMe:
    *wray.FayeClient does not implement Subscriber (wrong type for Subscribe method)
            have Subscribe(string, bool, func(wray.Message)) (wray.SubscriptionPromise, error)
            want Subscribe(string, bool, func(Message)) (Promise, error)

It seems as though it should work as the client does satisfy the interface:

// wray.go - wray.FayeClient
func (self *FayeClient) Subscribe(channel string, force bool, callback func(Message)) (promise SubscriptionPromise, err error) {
}

// response.go - wray.Message 
func (self Message) Data() map[string]interface{} {
}

// wray.go - wray.SubscriptionPromise
func (self SubscriptionPromise) Successful() bool {
}

It should work right? Or does the callback mess up the satisfaction of the interface?

Edit: as an aside, I am the author of that fork of the Faye Client, is there anything I can do to make it conducive to interfaces? Apart from ditching callbacks?

Upvotes: 1

Views: 2995

Answers (2)

cd1
cd1

Reputation: 16534

FayeClient.Subscribe implements:

Subscribe(string, bool, func(wray.Message)) (wray.SubscriptionPromise, error)

and your interface Subscriber requires the function:

Subscribe(string, bool, func(Message)) (Promise, error)

Notice the different parameters of the callback function (Message != wray.Message, Promise != wray.SubscriptionPromise), and that's why your code won't compile.

You don't need to declare the interfaces Message and Promise again, just use the ones from the library.

Upvotes: 4

LemurFromTheId
LemurFromTheId

Reputation: 4281

Despite what you claim, wray.FayeClient doesn't implement your Subscriber interface, because it's Subscribe method has a different signature from the one defined in your interface.

Subscribe(string, bool, func(wray.Message)) (wray.SubscriptionPromise, error) simply is not the same thing as Subscribe(string, bool, func(Message)) (Promise, error). wray.Message may implement Message, but it's still a different type. Same goes for wray.SubscriptionPromise and Promise.

If you want to make your library more conducive to interfaces, you need to change the library itself to accept interface arguments and return interfaces instead of concrete types.

Upvotes: 0

Related Questions