Why can't the interface be implemented with pointer receivers

21,390

Solution 1

Because it's *Faz not Faz.

func main() {
    foo := New().(*Faz)
    log.Println(foo)
}

Solution 2

I think the answer to this question needs to a more retrospective approach towards the grammar, and how would implement it through software engineering. (Excuse the over simplification)


First a quick flashback of what are types?
They are just memory blocks with compiler logic on top. What makes an array different from a string is what the compiler allows us to do with those memory blocks. (Think deeper and you may begin to realize the true difference between strongly typed and dynamically typed languages.)

Now next you need to realize that pointers are their own types per say.
*variable is a different memory block (aka type) than variable. It's just that the compiler always assumes that content of *variable is always going to be an address to a memory block of type to the right of the declaration along with other restriction/features it imposes.

Then let's recap what an interface is.
Pseudo-scientific definition: A set of requirements for any first class citizen to be of a specific type. Translated to software engineering- any block of memory (types) that has the same memory structure (think back to structure packing) associated to it as described in a contract (interface) can be passed around as with the type name that the contract mentions.


Now you may begin to realize that when you say

func (f *Faz) Bar() string is f's block of memory holding a function, where f's type is a pointer to Faz

where areas

func (f Faz) Bar() string is f's block of memory, where f's type is Faz

So when you are saying that a variable of *Faz type is satisfying a contract, then how can you assume that a variable of Faz type will qualify as interface type in the code? Chose who satisfies your contract, and only that type can assume the interface type in your code.

Share:
21,390
Daniel Robinson
Author by

Daniel Robinson

Projects API Dev @ Teamwork.com

Updated on July 09, 2022

Comments

  • Daniel Robinson
    Daniel Robinson almost 2 years

    I'm confused as to why this fails to compile with:

    impossible type assertion: Faz does not implement Foo (Bar method has pointer receiver)

    if I make the receiver for Faz.Bar a Faz value rather than a Faz pointer then it compiles fine, but I thought it was always better to have pointer receivers so values aren't being copied around?

    package main
    
    import (
        "log"
    )
    
    func main() {
        foo := New().(Faz)
        log.Println(foo)
    }
    
    type Foo interface {
        Bar() string
    }
    
    func New() Foo {
        return &Faz{}
    }
    
    type Faz struct {
    }
    
    func (f *Faz) Bar() string {
        return `Bar`
    }
    
  • Frederick F. Kautz IV
    Frederick F. Kautz IV almost 9 years
    They can be either *Faz or Faz but they all must match. Define them all Faz if you intend to return Faz{} or *Faz if you intend to return &Faz{}. How they maintain state is considered an implementation detail that you are basically hiding from the user.
  • Helin Wang
    Helin Wang about 7 years
    I don't agree with your explanation, following program works (type *foo satisfies String() defined for type foo):package main import ( "fmt" ) type foo struct{} func (f foo) String() string { return "111" } func main() { f := foo{} a := &foo{} var s fmt.Stringer s = a s = f fmt.Println(f.String(), a.String(), s) }