Please help me understand interfaces!

Hello everyone,

I’ve just been starting to learn go a bit over the past month when I have the time. I mostly program JavaScript on a day to day basis and I’ve also been programming in C a bit the past few months since I’ve been taking CS50 at my local college.

I’ve looked through a lot of Go material and written a little code here and there but one thing that’s driving me crazy is that I just don’t seem to get interfaces. I know it’s not that complicated and that’s why its bothering me so much. I was hoping someone else here might have had the same problem and can help me see it in the right light.

Everytime I go to try and write some Go code and I feel like I might be able to put some types and interfaces into play I just get lost. I’m going to continue to read material and take a deeper look through the standard library but any advice or tips are welcome!

Thanks

5 Likes

@danecando I thought this was a really good explanation of interfaces in Go: https://npf.io/2014/05/intro-to-go-interfaces/ (courtesy of @NateFinch).

Do you look at the code above (http://play.golang.org/p/erodX-JplO) and you ask yourself: why not, on line 24, instead of calling LongWalk(c), we don’t just call c.Walk(500)? If so, the issue is that you need to understand the why of interfaces. Why bother having that LongWalk function in there to begin with, right?

The answer to that is not bound by language, it is a design concept. Because I don’t have a link to one single great resource explaining it (there are so many), I think it would be more productive for you to search and see what explanation better grabs your attention.

And maybe this is not where you are stuck at all?

2 Likes

My short answer before heading off to bed:

  • Think of an interface as a contract - i.e. if you implement the methods I define, you’re satisfying that interface. e.g. any type that has a ServeHTTP(http.ResponseWriter, *http.Request) method on it can satisfy http.Handler (https://golang.org/pkg/net/http/#Handler). Another example would be io.Writer (https://golang.org/pkg/io/#Writer) - provide a type with a Write([]byte) (int, error) method on it and your type will be accepted by anything expecting a io.Writer. An interface might require multiple methods: your type must implement all of them to satisfy the interface.
  • An interface with methods defined and the empty interface - what you see as interface{} - can be a source of confusion. Every type satisfies the empty interface (because it has no methods) and hence it’s often used as a way to accept any type, to potentially be type-cast back later to its concrete (non-interface type).

If you haven’t read Effective Go yet, I’d recommend doing so.

3 Likes

Hi Dan,

First thing first is to understand why you would use an interface.
One simple sample would be for an abstraction level that you need. In your application you have some Cats and Dogs and they have in common some function like Born(), Eat(), Sleep() or Die(). if you have in your function signature an Interface like Animal in the parameter you can simply use Animal instead of. Take a look to this sample

Then you can go the different type of implementations :
Simple interface
Interface of interface (same website)

I hope this will help you.

2 Likes

Thanks for the feedback gang. I think maybe I’m just overthinking it a bit to much… Just a little to green to be knowing what I don’t know.

@carlisia thanks for that link it was a big help. Spent the past few hours studying on that and a couple other resources and I think I’m starting to get it.

I’m sure the rest will come to me with more experience and practice. Better get to coding :smile:

3 Likes

I agree, I was overthinking about Interfaces too some time back. There was a time when I was thinking that why do I even need Interfaces. But one fine day I just decided that I should use interface for my problem instead of a concrete type and voila, I got all my answers. So I will suggest, just use interface once and you will see what how helpful they are.

1 Like

Interfaces didn’t fully click for me until I had to work with other people’s interfaces. Working with http.Handler, http.HandlerFunc was the first eye opener for me. A good practice I try to follow is to always read the standard implementation when working with a new interface.

1 Like

I’m working on my first actual Go program atm and I’m contemplating my first interface. Please let me know if I’m on the right track here…

So I’m setting up a basic http server that will handle some background processing for other sites / services. In particular right now I’m going to be parsing JSON, downloading images, uploading them to an S3 bucket, and writing to a sql database.

For the file / image uploading I was thinking about something like this:

  • An interface called Uploader with an Upload function
  • Possibly an Upload struct that represents a file that is ready for upload (opened, type checked, etc)
  • A New or Create function that takes in a path and returns an instance of the upload struct

With those pieces in place I can have a specific local server uploader that implements the interface and an aws uploader that implements it, etc etc

Does it seem like I’m on the right track? If not some suggestions are welcomed :smile:

Thanks gang!

That looks right. Just make sure Upload struct implements interface by having a method called upload.

Your Uploader interface can look like this

   type Uploader interface {
      Upload(io.Writer) error
   }

And it will work regardless of transport.

@danecando here’s another idea which helped interfaces “click” for me:

take a struct that has a bunch of funcs on it (would be called “methods” in OOP languages) and create an interface with a few of those function signatures in it. Then, change a function that used to take the struct type to take in the interface type. Watch everything work the same after you re-compile and run. The key learning in there is that you don’t have to change anything else in order to have your types adhere to an interface.

Here’s a contrived example:

// Number is the result of adding Number1 and Number2
type Number struct {
  Number int
}

func (n Number) Add(i int) int {
  return n.Number1+n.Number2+i
}

func (n Number) Sub(i int) int {
  return n.Number1+n.Number2-1
}

type Integer int

func (i Integer) Add(i1 int) int {
  return i + i1
}

func (i Integer) Mult(i1 int) int {
  return i * i1
}

// Both Integer and Number _automatically_ adhere to this interface.
// all 3 types may be in different packages, with no knowledge of
// each other and that fact will still be true.
type Adder interface {
  // This means that a type that adheres to Adder must 
  // have Add defined with that type as the receiver
  Add(int) int
}

Note that both Integer and Number have other funcs that aren’t in Adder, and they also have different funcs from each other. Neither fact matters because interfaces only list the funcs that types must have, not ones they must not or anything else.

Also, sidenote - it’s best practice to make interfaces have an ‘-er’ suffix.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.