T Suds
T Suds

Reputation: 337

Go Interfaces that use the interface in the definition

I am playing around with making a Fibonacci Heap. (They are mentioned several times in an algorithms class that I'm taking, and I want to check them out.) I want the heap to use nodes of any kind, so I define a Node interface:

package node

type Node interface {
    AddChild(other Node)
    Less(other Node) bool
}

type NodeList []Node

func (n NodeList) AddNode(a Node) {
    n = append(n, a)
}

(I use the []Node array because it has the same affect as the heap definition.) As you can see, the Node interface defines its two functions with arguments of type Node. This should mean that the functions have to accept arguments that implement the Node interface. The rest of the heap uses these nodes.

In the program that uses this heap, I make a type that implements the Node interface:

package main

import "container/list"
import node "./node"

type Element struct {
    Children *list.List
    Value int
}

func (e Element) AddChild(f Element) {
    e.Children.PushBack(f)
}

func (e Element) Less(f Element) bool {
    return e.Value < f.Value
}

func main() {
    a := Element{list.New(), 1}

    n := new(node.NodeList)
    n.AddNode(a)
}

However, this didn't work. The compiler complains that Element doesn't have the correct function definitions for the interface.

cannot use a (type Element) as type node.Node in function argument:
Element does not implement node.Node (wrong type for AddChild method)
    have AddChild(Element)
    want AddChild(node.Node)

What is wrong here? Obviously Element doesn't implement the interface correctly, but I think it's because of how I defined the interface. Is there a correct way to do what I want in Go? Can interfaces refer to themselves?

Upvotes: 4

Views: 197

Answers (1)

Lily Ballard
Lily Ballard

Reputation: 185653

The function

func (e Element) Less(f Element) bool

does not match the function from the interface

func Less(other Node) bool

You need to actually match the signature, as in

func (e Element) Less(f Node) bool

And yes, this means you could be passed a Node that isn't an Element. You'll have to test for that at runtime and panic.


As an example for why this is so, consider if your code was legit, and I tried the following:

type Other int
func (o Other) Less(f Other) bool {
    return o < f
}
func (o Other) AddChild(f Other) {}
e = GetSomeElement() // of type Element
var o Other
var n Node = e
fmt.Println(n.Less(o))

Because I stored the Element into a var of type Node, I can now call Less() with an argument that isn't another Element, which violates the type of Element.Less(). This is why that's not legal.

Upvotes: 6

Related Questions