Jesse Brands
Jesse Brands

Reputation: 2877

Go: function callback returning implementation of interface

I got a system that handles the resolving of resources (matching a name to a file path, etc). It parses a list of files and then keeps pointers to a function that returns an instance of an implementation of an interface.

It's easier to show.

resource.go

package resource

var (
    tex_types    map[string]func(string) *Texture = make(map[string]func(string) *Texture)
    shader_types map[string]func(string) *Shader  = make(map[string]func(string) *Shader)
)

type Texture interface {
    Texture() (uint32, error)
    Width() int
    Height() int
}

func AddTextureLoader(ext string, fn func(string) *Texture) {
    tex_types[ext] = fn
}

dds.go

package texture

type DDSTexture struct {
    path   string
    _tid   uint32
    height uint32
    width  uint32
}

func NewDDSTexture(filename string) *DDSTexture {
    return &DDSTexture{
        path:   filename,
        _tid:   0,
        height: 0,
        width:  0,
    }
}


func init() {
    resource.AddTextureLoader("dds", NewDDSTexture)
}

DDSTexture fully implements the Texture interface, I just omitted those functions because they're huge and not part of my question.

When compiling these two packages, the following error arises:

resource\texture\dds.go:165: cannot use NewDDSTexture (type func(string) *DDSTexture) as type func (string) *resource.Texture in argument to resource.AddTextureLoader

How would I resolve this problem, or is this a bug with the interface system? Just reiterating: DDSTexture fully implements resource.Texture.

Upvotes: 2

Views: 1119

Answers (1)

VonC
VonC

Reputation: 1323553

Yes, DDSTexture fully implements resource.Texture.

But the named type NewDDSTexture (type func(string) *DDSTexture) isn't the same as the unamed type func (string) *resource.Texture: their type identity doesn't match:

Two function types are identical if they have the same number of parameters and result values, corresponding parameter and result types are identical, and either both functions are variadic or neither is. Parameter and result names are not required to match.

A named and an unnamed type are always different.

Even if you defined a named type for your function, it wouldn't work:

type FuncTexture func(string) *Texture
func AddTextureLoader(ext string, fn FuncTexture)

cannot use NewDDSTexture (type func(string) `*DDSTexture`) 
as type `FuncTexture` in argument to `AddTextureLoader`

Here, the result value type don't match DDSTexture vs. resource.Texture:
Even if one implements the interface of the other, their underlying type still differ): you cannot assign one to the other.

You need for NewDDSTexture() to return Texture (no pointer, since it is an interface).

func NewDDSTexture(filename string) Texture

See this example.

As I explained in "Cast a struct pointer to interface pointer in golang", you usually don't need a pointer to an interface.

Upvotes: 5

Related Questions