-1

This code does not run correctly :

package main
import "fmt"

type Human interface {
    myStereotype() string
}

type Man struct {
}

func (m Man) myStereotype() string {
    return "I'm going fishing."
}

type Woman struct {
}

func (m Woman) myStereotype() string {
    return "I'm going shopping."
}
func main() {
    var m *Man
    m = new (Man)
    w := new (Woman)

    var hArr []*Human

    hArr = append(hArr, m)
    hArr = append(hArr, w)

    for n, _ := range (hArr) {

        fmt.Println("I'm a human, and my stereotype is: ",
                hArr[n].myStereotype())
    }
}

It exists with :

tmp/sandbox637505301/main.go:29:18: cannot use m (type *Man) as type *Human in append:
*Human is pointer to interface, not interface
tmp/sandbox637505301/main.go:30:18: cannot use w (type *Woman) as type *Human in append:
*Human is pointer to interface, not interface
tmp/sandbox637505301/main.go:36:67: hArr[n].myStereotype undefined (type *Human is pointer to interface, not interface)

But this one runs correctly (var hArr []*Human is rewritten into var hArr []Human) :

package main
import "fmt"

type Human interface {
    myStereotype() string
}

type Man struct {
}

func (m Man) myStereotype() string {
    return "I'm going fishing."
}

type Woman struct {
}

func (m Woman) myStereotype() string {
    return "I'm going shopping."
}
func main() {
    var m *Man
    m = new (Man)
    w := new (Woman)

    var hArr []Human // <== !!!!!! CHANGED HERE !!!!!!

    hArr = append(hArr, m)
    hArr = append(hArr, w)

    for n, _ := range (hArr) {

        fmt.Println("I'm a human, and my stereotype is: ",
                hArr[n].myStereotype())
    }
}

Output is ok:

I'm a human, and my stereotype is:  I'm going fishing.
I'm a human, and my stereotype is:  I'm going shopping.

And I do not understand why. As m and w are pointers, why when I define hArr as an array of pointers on Human the code fails ?

Thank you for your explanation

  • 3
    Go has no inheritance, hence there is no "is a" type polymorphism. – JimB Nov 06 '17 at 16:17
  • Possible duplicate of [Using Interfaces to Create a Queue for Arbitrary Types](https://stackoverflow.com/questions/35595810/using-interfaces-to-create-a-queue-for-arbitrary-types) – kylieCatt Nov 06 '17 at 21:46

2 Answers2

4

Your primary problem is that you're using a pointer to an interface. My answer to this question contains some details about the difference. Suffice it to say, pointers to interfaces are almost always errors.

If you store a *Man into a Human (NOT a *Human), it'll work just fine because interfaces can store pointers without a problem. In fact, in general, you want to default to storing pointers in interfaces, as values stored in interfaces cannot access pointer methods of the type stored. An interface is simply a bucket that holds a type, and it doesn't matter whether that type is a struct or a pointer to a struct. A pointer to an interface, on the other hand, is NOT an interface, and doesn't have the same implicit fulfillment system that interfaces have. It's much the same as being unable to use a *func() variable as a function. It's a pointer, not a function.

TL;DR: don't use pointers to interfaces. It's almost never useful, and generally just reflects a misunderstanding of what interfaces are.

Kaedys
  • 9,600
  • 1
  • 33
  • 40
2

It might help to think about interfaces as more similar to an API definition than a type. Things that satisfy the interface can already be structs or pointers, so you don't need to use an interface pointer. As stated in this excellent answer:

Pointers to interfaces are almost never useful. In fact, the Go runtime was specifically changed a few versions back to no longer automatically dereference interface pointers (like it does for structure pointers), to discourage their use. In the overwhelming majority of cases, a pointer to an interface reflects a misunderstanding of how interfaces are supposed to work.

Dave Gray
  • 715
  • 5
  • 11