Meaning of a struct with embedded anonymous interface?

Ok, the accepted answer helped me understand, but I decided to post an explanation which I think suits better my way of thinking.

The "Effective Go" has example of interfaces having embedded other interfaces:

// ReadWriter is the interface that combines the Reader and Writer interfaces.
type ReadWriter interface {
    Reader
    Writer
}

and a struct having embedded other structs:

// ReadWriter stores pointers to a Reader and a Writer.
// It implements io.ReadWriter.
type ReadWriter struct {
    *Reader  // *bufio.Reader
    *Writer  // *bufio.Writer
}

But there is no mention of a struct having embedded an interface. I was confused seeing this in sort package:

type Interface interface {
    Len() int
    Less(i, j int) bool
    Swap(i, j int)
}

...

type reverse struct {
    Interface
}

But the idea is simple. It's almost the same as:

type reverse struct {
    IntSlice  // IntSlice struct attaches the methods of Interface to []int, sorting in increasing order
}

methods of IntSlice being promoted to reverse.

And this:

type reverse struct {
    Interface
}

means that sort.reverse can embed any struct that implements interface sort.Interface and whatever methods that interface has, they will be promoted to reverse.

sort.Interface has method Less(i, j int) bool which now can be overridden:

// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

My confusion in understanding

type reverse struct {
    Interface
}

was that I thought that a struct always has fixed structure, i.e. fixed number of fields of fixed types.

But the following proves me wrong:

package main

import "fmt"

// some interface
type Stringer interface {
    String() string
}

// a struct that implements Stringer interface
type Struct1 struct {
    field1 string
}

func (s Struct1) String() string {
    return s.field1
}


// another struct that implements Stringer interface, but has a different set of fields
type Struct2 struct {
    field1 []string
    dummy bool
}

func (s Struct2) String() string {
    return fmt.Sprintf("%v, %v", s.field1, s.dummy)
}


// container that can embedd any struct which implements Stringer interface
type StringerContainer struct {
    Stringer
}


func main() {
    // the following prints: This is Struct1
    fmt.Println(StringerContainer{Struct1{"This is Struct1"}})
    // the following prints: [This is Struct1], true
    fmt.Println(StringerContainer{Struct2{[]string{"This", "is", "Struct1"}, true}})
    // the following does not compile:
    // cannot use "This is a type that does not implement Stringer" (type string)
    // as type Stringer in field value:
    // string does not implement Stringer (missing String method)
    fmt.Println(StringerContainer{"This is a type that does not implement Stringer"})
}

The statement

type reverse struct {
    Interface
}

enables you to initialize reverse with everything that implements the interface Interface. Example:

&reverse{sort.Intslice([]int{1,2,3})}

This way, all methods implemented by the embedded Interface value get populated to the outside while you are still able to override some of them in reverse, for example Less to reverse the sorting.

This is what actually happens when you use sort.Reverse. You can read about embedding in the struct section of the spec.


In this way reverse implements the sort.Interface and we can override a specific method without having to define all the others

type reverse struct {
        // This embedded Interface permits Reverse to use the methods of
        // another Interface implementation.
        Interface
}

Notice how here it swaps (j,i) instead of (i,j) and also this is the only method declared for the struct reverse even if reverse implement sort.Interface

// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
        return r.Interface.Less(j, i)
}

Whatever struct is passed inside this method we convert it to a new reverse struct.

// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
        return &reverse{data}
}

The real value comes if you think what would you have to do if this approach was not possible.

  1. Add another Reverse method to the sort.Interface ?
  2. Create another ReverseInterface ?
  3. ... ?

Any of this change would require many many more lines of code across thousands of packages that want to use the standard reverse functionality.


I will give my explanation too. The sort package defines an unexported type reverse, which is a struct, that embeds Interface.

type reverse struct {
    // This embedded Interface permits Reverse to use the methods of
    // another Interface implementation.
    Interface
}

This permits Reverse to use the methods of another Interface implementation. This is the so called composition, which is a powerful feature of Go.

The Less method for reverse calls the Less method of the embedded Interface value, but with the indices flipped, reversing the order of the sort results.

// Less returns the opposite of the embedded implementation's Less method.
func (r reverse) Less(i, j int) bool {
    return r.Interface.Less(j, i)
}

Len and Swap the other two methods of reverse, are implicitly provided by the original Interface value because it is an embedded field. The exported Reverse function returns an instance of the reverse type that contains the original Interface value.

// Reverse returns the reverse order for data.
func Reverse(data Interface) Interface {
    return &reverse{data}
}

Tags:

Go