7

I found an interesting blog post about Go.

I am trying to understand the concept of interfaces, but I find it very hard to do so from the code fragment in the blog post, and nearly impossible from the language specification.

Can anyone point out a simple example of Go's interfaces in a working program?

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • A few resources that might help: https://gobyexample.com/interfaces + http://www.laktek.com/2012/02/13/learning-go-interfaces-reflections/ + http://golangtutorials.blogspot.com.au/2011/06/interfaces-in-go.html – elithrar Jun 10 '13 at 00:24
  • Examples of Go interfaces? Decouple code. See https://stackoverflow.com/a/62297796/12817546. Call a method “dynamically”. See https://stackoverflow.com/a/62336440/12817546. Access a Go package. See https://stackoverflow.com/a/62278078/12817546. Assign any value to a variable. See https://stackoverflow.com/a/62337836/12817546. –  Jul 10 '20 at 09:54

6 Answers6

4

The tutorial "Interfaces in Go - Part 2: Aiding adaptable, evolutionary design " (January 2012, from Sathish VJ) mentions clearly the main advantage for interfaces in Go:

Go's interfaces aren't a variant on Java or C# interfaces, they're much more.
They are a key to large-scale programming and adaptable, evolutionary design.

See this example, from the same article, about different perspective (interface) for a Bus:

package main

import "fmt"

//Go Step 1: Define your data structures
type Bus struct {
    l, b, h int
    rows, seatsPerRow int
}

//Go Step 2: Define a real world abstraction that could use the data we structure we have
type Cuboider interface {
    CubicVolume() int
}

//Go Step 3: Implement methods to work on data
func (bus Bus) CubicVolume() int {
    return bus.l *  bus.b * bus.h
}

//Go step - repeat 2 & 3 for any other interfaces
type PublicTransporter interface  {
    PassengerCapacity() int
}

func (bus Bus) PassengerCapacity() int {
    return bus.rows * bus.seatsPerRow
}

func main() {
    b := Bus{
             l:10, b:6, h:3,
             rows:10, seatsPerRow:5}

    fmt.Println("Cubic volume of bus:", b.CubicVolume())
    fmt.Println("Maximum number of passengers:", b.PassengerCapacity())
}

It appears to be data centric - define your data first and build your interface abstractions as you go along.
Hierarchy here is kind of built 'along the way' without explicitly stating it - depending on the method signatures associated with the type, it is understood as implementing specific interfaces.

Let us assume now that as time evolved, some of the project requirements for our Bus changed - there is now a new law that says that each passenger should at least have a certain minimum amount of cubic volume.
Our Bus now now has to adhere to a new interface called PersonalSpaceLaw which is distinct from any of the other interfaces it already implements

//new requirement that the Bus must be compatible with
type PersonalSpaceLaw interface {
    IsCompliantWithLaw() bool
}

func (b Bus) IsCompliantWithLaw() bool {
    return (b.l * b.b * b.h) / (b.rows * b.seatsPerRow) >= 3
}

The functionality has been extended without any change to the core classes or core hierarchies. This implementation is much cleaner, easily extensible, and can scale better with the changing needs of the project's requirements.

Here is the full working program in Go Playground

The article ends with John Asmuth's quote from from the thread about the productivity of interfaces in Go:

"It's the fact that I don't have to spend time up front designing some sort of type hierarchy and then rearranging it two or three times before I finish.
It's not even the fact that it's easy to do it right -
it's the fact that I just don't have to worry about it and can get on with the actual algorithm."

VonC
  • 1,262,500
  • 529
  • 4,410
  • 5,250
  • I know you posted this a while ago, but it's a great example so thanks! – Xeoncross Oct 25 '12 at 02:32
  • Very nice example, explanation and quotes. +1 – phw Nov 19 '13 at 17:12
  • 1
    Not sure how this is an example of anything at all. Here is the same code where interfaces were just deleted, working just fine: https://play.golang.org/p/WXpl78MAQrV – Vadym Tyemirov Oct 25 '18 at 00:56
  • @VonC Top-notch answer about defining your data first and then building your interface. I upvoted your answer and quoted it. See https://stackoverflow.com/a/62297796/12817546. –  Jul 10 '20 at 10:20
  • 1
    @TomJ I like too https://lbry.tv/@dfeury:5/Interfaces-in-Go-are-SO-GOOD---Go---Golang-Interface-Tutorial-_--feurious:5, and https://twitter.com/davecheney/status/942593128355192832?s=19 – VonC Jul 10 '20 at 10:27
4

It's a work-in-progress learning exercise, and certainly a poor example of good style, but here you go (spec).

Additionally, as a more exotic example, I made a post on the go-nuts mailing list regarding using interface{} for building functions that work with anonymous data (in this case, a "ternary operation" function):

package main
import "fmt";
func Tern(exp bool, a interface{}, b interface{}) (interface{}) {
    if exp { return a }
    return b
}
func main() {
    a := 7; b := 1;
    result := Tern(a > b, a, b);
    fmt.Printf("%d\n", result);
}
mvanveen
  • 9,754
  • 8
  • 33
  • 42
esm
  • 1,730
  • 15
  • 10
  • Thanks, I'll have a look at your example. I want a piece of compiling code to work with so this looks good. –  Nov 14 '09 at 16:32
  • What does `interface{}` mean here? –  Nov 15 '09 at 00:31
  • "interface{}" is an empty interface; in other words, it matches all types. Think of it as an "any" value: a means of writing generic functions that can operate on any value. Sadly, the documentation sorely lacks here; this, along with the "reflection" package, give you some really interesting options for type manipulation. – esm Nov 15 '09 at 04:19
  • I was looking at some of the library code about `reflect` but ended up a bit confused. It's used a lot in the `Printf` routines where the type of the variables is got from the variables themselves. But I got lost in a twisty maze of dependencies, all alike. –  Nov 15 '09 at 08:33
  • This example works just fine if the `interface` are replaced with `int`. See https://play.golang.org/p/ww-5ma7m5IS. –  Jun 04 '20 at 02:55
2
package main

type Stringer interface {
    String() string
}

type pie int
type pizza string

func (p pie) String() string{
    return "pie"
}

func (p pizza) String() string{
    return "pizza"
}

func main(){
    var a pie
    var b pizza
    fmt.Println(a,b) //fmt.Println() will look for Stringers and call their String() method.
}
mjohnson
  • 138
  • 1
  • 9
Jesse
  • 2,802
  • 20
  • 12
1

Extending @Jessta excellent example. A simple example of the use of Go's' interface in a working program to access Go's standard library is given.

package main

import (
    "encoding/json"
    . "fmt"
)

func main() {
    var i interface{} = c

    e := func() error { return c } // type error interface { Error() string}
    Println(e())                   // Hiss

    s := func() Stringer { return d } // type Stringer interface {String() string}

    // func Println(a ...interface{}) (n int, err error)
    Println(s()) // Woof

    d := `{"Pet":"Dog","Age":2, "Eat": "Bone"}`
    json.Unmarshal([]byte(d), &i) // func Unmarshal(data []byte, v interface{}) error
    m := i.(map[string]interface{})
    Println(m["Age"]) // 2
}

type cat string
type dog string
var c cat
var d dog
func (cat) Error() string { return "Hiss" }
func (dog) String() string { return "Woof" }

Interfaces are Go's most distinctive and powerful feature. They have a profound effect on library design. They enable true component architectures. Prime examples are io.Reader and io.Writer, generalizations of the Unix pipe idea. See https://talks.golang.org/2015/simplicity-is-complicated.slide.

By convention, errors have type error, a simple built-in interface. See https://golang.org/doc/effective_go.html#errors and https://talks.golang.org/2012/splash.article. An error variable represents any value that can describe itself as a string. func() error { return c } calls type error interface { Error() string}. func (cat) Error() string implements type error interface { Error() string}. See https://blog.golang.org/error-handling-and-go.

A Stringer can pretty print itself. Anything that implements String is a Stringer. fmt.Println calls the String method if the parameter is a Stringer. See https://talks.golang.org/2013/go4python.slide#33. func() Stringer { return d } calls type Stringer interface {String() string}. func (dog) String() string implements type Stringer interface {String() string}.

The signature of fmt.Println is func Println(format string, a ...interface{}) (n int, err error) which is to say its arguments (after the format string) are interface values. See https://blog.golang.org/constants. Quotes edited to match example.

Pervasive use of key interfaces in the standard library make it easy to chain APIs together. See https://talks.golang.org/2012/goforc.slide#46. See https://talks.golang.org/2014/go4gophers and https://talks.golang.org/2014/go4gophers.slide#1 for more examples.

  • Decouple code with an interface. See https://stackoverflow.com/a/62297796/12817546. Call a method “dynamically”. See https://stackoverflow.com/a/62336440/12817546. Access a Go package. See https://stackoverflow.com/a/62278078/12817546. Assign any value to a variable. See https://stackoverflow.com/a/62337836/12817546. –  Jul 10 '20 at 09:17
0

Wikipedia explains duck-typing and has an example in Go. http://en.wikipedia.org/wiki/Duck_typing

user2468968
  • 286
  • 3
  • 9
0

The base concept of interfaces in Go, is that any object implementing a method defined an interface, can be a part of that interface.

The best example is the Writer interface. Rob Pike has an example of this in his intro speech at Google Tech Talk ( http://www.youtube.com/watch?v=rKnDgT73v8s ) - scroll to 33:25 into the speech for his explanation.

Björn
  • 29,019
  • 9
  • 65
  • 81