4

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?

1 Answer 1

6

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Oh. Well that's no fun, I guess. I was hoping that I was missing something and that there would be a way for it to just match interface types. Now that I think about it, that doesn't really make sense, since the Element type is stricter than the Node type. Would I use the runtime package to test for the type?
@TSuds: No, you can just use a type assertion, as in other = f.(Element). If this assertion fails it will panic for you.
@TSuds, consider reading this classical post to better understand how interfaces work in Go (and why there's no such thing as one type being "stricter" than another, as you'd expect)

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.