Interfaces in Go with example


Image Courtesy at blog.darrencannell.com
Basically, almost all the programmers irrespective of any language, they might be using interfaces knowingly or unknowingly while programming the applications. This post will be kind of detail about explaining what an interface is, how it is used in the real-time scenarios, examples, definitions and the naming conventions. I would try to help you in understanding as much as possible. I assume that you are aware of the Go language at-least somewhat, if not please read the doc from http://golang.org

What are interfaces?
In real-time, the interfaces look something like this…
34_button_remote_charcoal_picture
even this is also an interface…
microwave
even this is also an interface…
compatible-ps2-dual-shock-vibration-joystick-game-controller-bulk-chocobozz-1106-19-Chocobozz@121
even this too is an interface…
2014-Honda-Odyssey-Exterior-Door-Handle

There are many definitions, but I will take those which are related to the golang:

Interfaces in Go provide a way to specify the behavior or an object: if something can do this, then it can be used here.

https://golang.org/doc/effective_go.html#interfaces

In object-oriented languages, the term interface is often used to define an abstract type that contains no data or code, but defines behaviors as method signatures. A class having code and data for all the methods corresponding to that interface is said to implement that interface.

http://en.wikipedia.org/wiki/Interface_(computing)#Software_interfaces_in_object-oriented_languages

An interface is an abstract class / method that is intended to be used as a common base to access a number of similarly behaving objects. Conceptually, there is no requirement for abstractness, but usually, an interface will have at least one abstract method. An interface is a method for your program to communicate with a number of similar classes, each with different semantics but the same general purpose.

http://stackoverflow.com/questions/219425/interface-contract-class-object

An interface is a description of the actions that an object can do.

http://www.cs.utah.edu/~germain/PPS/Topics/interfaces.html

By reading all the above definitions, you might have got little confused!!!! Initially, even I got confused little bit, and later I understood, here is the my simple 3 point definition:

  • Interfaces are just an identity definition not functionality but defines the common functionality across unrelated methods.
  • An interface is a contractual obligation (or a rule) to implement certain methods, properties and events.
  • Implementations of the interface, don’t have to know how they will be used, they just have to know they will be expected to provide methods.

Go Interface Syntax

type <name_of_interface> interface {
     <action_to_be_done>
}

Scenario (Example)
Lets take a scenario to understand better, assume that you need program for a school to enroll their students & employee, so we will treat Student as an object & Employee as well as an object. Now Student & Employee has different properties, such as Student object will have the following properties like Name, Grade, Gender, etc., and Employee Object will have its own properties something like this Name, Gender, Qualification, Shift, etc.,



Interface 1-1
Now both the Student and Employee has the same similarity that they both need to be enrolled. Lets forget for a moment about the interfaces and lets code this in Go, which will look similar like the below:

package main

import "fmt"

// Student Structure has 3 properties (Name, Grade, Gender)
type Student struct {
	Name   string
	Grade  string
	Gender string
}

// Enroll registers the Students
// It reads the student information and displays those details.
// Error handling is not done here.
func (s Student) Enroll() {
	fmt.Println("Received the details of Student")
	fmt.Println("Name    : ", s.Name)
	fmt.Println("Grade   : ", s.Grade)
	fmt.Println("Gender  : ", s.Gender)
	fmt.Println("Student Enrolled!!!")
	return
}

// Employee Structure has 4 properties (name, Gender, Qualification, Shift)
type Employee struct {
	Name          string
	Gender        string
	Qualification string
	Shift         int // Morning shift - AM - 0 or Afternoon shift - PM - 1
}

// Enroll registers the Employees
// It reads the employee information and displays those details.
// Error handling is not done here.
func (e Employee) Enroll() {
	fmt.Println("Received the details of Employee")
	fmt.Println("Name          : ", e.Name)
	fmt.Println("Gender        : ", e.Gender)
	fmt.Println("Qualification : ", e.Qualification)
	fmt.Println("Shift Opted   : ", e.Shift)
	fmt.Println("Employee Enrolled!!!")
	return
}

func main() {
	fmt.Println("Welcome to School")

	// Lets create a student object & enroll
	m_st1 := Student{Name: "Student 1", Grade: "1", Gender: "Male"}
	m_st1.Enroll()

	fmt.Println("--------------------------")

	// Lets create an employee object & enroll
	m_em1 := Employee{Name: "Employee 1", Gender: "Male", Qualification: "Masters Degree", Shift: 0}
	m_em1.Enroll()

	fmt.Println(" - Bye!")
}

The output for the above code is

Welcome to School
Received the details of Student
Name : Student 1
Grade : 1
Gender : Male
Student Enrolled!!!
--------------------------
Received the details of Employee
Name : Employee 1
Gender : Male
Qualification : Masters Degree
Shift Opted : 0
Employee Enrolled!!!
- Bye!

Now lets look how interface can be used, I have added interface and also the way Enroll method is called,
Interface 1-2

look at the below code especially the highlighted lines:

package main

import "fmt"

// Enroller is an interfance for Student & Employee object
type Enroller interface {
	Enroll()
}

// Student Structure has 3 properties (Name, Grade, Gender)
type Student struct {
	Name   string
	Grade  string
	Gender string
}

// Enroll registers the Students
// It reads the student information and displays those details.
// Error handling is not done here.
func (s Student) Enroll() {
	fmt.Println("Received the details of Student")
	fmt.Println("Name    : ", s.Name)
	fmt.Println("Grade   : ", s.Grade)
	fmt.Println("Gender  : ", s.Gender)
	fmt.Println("Student Enrolled!!!")
	return
}

// Employee Structure has 4 properties (name, Gender, Qualification, Shift)
type Employee struct {
	Name          string
	Gender        string
	Qualification string
	Shift         int // Morning shift - AM - 0 or Afternoon shift - PM - 1
}

// Enroll registers the Employees
// It reads the employee information and displays those details.
// Error handling is not done here.
func (e Employee) Enroll() {
	fmt.Println("Received the details of Employee")
	fmt.Println("Name          : ", e.Name)
	fmt.Println("Gender        : ", e.Gender)
	fmt.Println("Qualification : ", e.Qualification)
	fmt.Println("Shift Opted   : ", e.Shift)
	fmt.Println("Employee Enrolled!!!")
	return
}

func main() {
	fmt.Println("Welcome to School")

	// Lets create a student object & enroll
	m_st1 := Student{Name: "Bryan", Grade: "1", Gender: "Male"}

	// Lets initialize the Enroller
	var e Enroller
	e = m_st1
	e.Enroll()

	fmt.Println("--------------------------")

	// Lets create an employee object & enroll
	m_em1 := Employee{Name: "John", Gender: "Male", Qualification: "Masters Degree", Shift: 0}
	e = m_em1
	e.Enroll()

	fmt.Println(" - Bye!")
}

The output for the above code still remains the same as previous

Welcome to School
Received the details of Student
Name : Student 1
Grade : 1
Gender : Male
Student Enrolled!!!
--------------------------
Received the details of Employee
Name : Employee 1
Gender : Male
Qualification : Masters Degree
Shift Opted : 0
Employee Enrolled!!!
- Bye!

Hopefully, you would be thinking, why extra code, when it can be achieved without adding interface code, right? Wait, continue reading, you will understand more in a bit. Now lets add one more complexity, right now there are only one student & one employee, lets add a bunch more students & employees and the snippet of the code looks like this:

Interface 2-1

package abc
func main() {
	fmt.Println("Welcome to School")

	// Lets create few student objects
	m_st1 := Student{Name: "Student 1", Grade: "1", Gender: "Male"}
	m_st2 := Student{Name: "Student 2", Grade: "2", Gender: "Female"}
	m_st3 := Student{Name: "Student 3", Grade: "3", Gender: "Male"}
	m_st4 := Student{Name: "Student 4", Grade: "4", Gender: "Female"}
	m_st5 := Student{Name: "Student 5", Grade: "5", Gender: "Male"}

	// Lets create an employees
	m_em1 := Employee{Name: "Employee 1", Gender: "Male", Qualification: "Masters Degree", Shift: 0}
	m_em2 := Employee{Name: "Employee 2", Gender: "Female", Qualification: "Masters Degree", Shift: 0}
	m_em3 := Employee{Name: "Employee 3", Gender: "Male", Qualification: "Bachelors Degree", Shift: 1}
	m_em4 := Employee{Name: "Employee 4", Gender: "Female", Qualification: "Masters Degree", Shift: 1}
	m_em5 := Employee{Name: "Employee 5", Gender: "Male", Qualification: "Bachelors Degree", Shift: 0}

	// Lets collect all the objects in one array
	e := [...]Enroller{m_st1, m_st2, m_st3, m_st4, m_st5, m_em1, m_em2, m_em3, m_em4, m_em5}
	for i, _ := range e {
		e[i].Enroll()
	}

	fmt.Println(" - Bye!")
}

The output is bigger now…

Welcome to School
Received the details of Student
Name    :  Student 1
Grade   :  1
Gender  :  Male
Student Enrolled!!!
Received the details of Student
Name    :  Student 2
Grade   :  2
Gender  :  Female
Student Enrolled!!!
Received the details of Student
Name    :  Student 3
Grade   :  3
Gender  :  Male
Student Enrolled!!!
Received the details of Student
Name    :  Student 4
Grade   :  4
Gender  :  Female
Student Enrolled!!!
Received the details of Student
Name    :  Student 5
Grade   :  5
Gender  :  Male
Student Enrolled!!!
Received the details of Employee
Name          :  Employee 1
Gender        :  Male
Qualification :  Masters Degree
Shift Opted   :  0
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 2
Gender        :  Female
Qualification :  Masters Degree
Shift Opted   :  0
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 3
Gender        :  Male
Qualification :  Bachelors Degree
Shift Opted   :  1
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 4
Gender        :  Female
Qualification :  Masters Degree
Shift Opted   :  1
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 5
Gender        :  Male
Qualification :  Bachelors Degree
Shift Opted   :  0
Employee Enrolled!!!
 - Bye!

Cool Isn’t?!! Now lets add one more complexity, lets say the few students & few employees have Submitted their details like photo etc., and now the code looks like this:

Interface 2-2

package main

import "fmt"

// Admitter is an interface for Student & Employee object
type Admitter interface {
	Enroll()
	Submit() string
}

// Student Structure has 3 properties (Name, Grade, Gender)
type Student struct {
	Name   string
	Grade  string
	Gender string
}

// Enroll registers the Students
// It reads the student information and displays those details.
// Error handling is not done here.
func (s Student) Enroll() {
	fmt.Println("Received the details of Student")
	fmt.Println("Name    : ", s.Name)
	fmt.Println("Grade   : ", s.Grade)
	fmt.Println("Gender  : ", s.Gender)
	fmt.Println("Student Enrolled!!!")
	return
}

// Submit saves the details submitted by the Students
// It reads the student information and displays those details.
// Error handling is not done here.
func (s Student) Submit() string {
	return s.Name + " submitted details."
}

// Employee Structure has 4 properties (name, Gender, Qualification, Shift)
type Employee struct {
	Name          string
	Gender        string
	Qualification string
	Shift         int // Morning shift - AM - 0 or Afternoon shift - PM - 1
}

// Enroll registers the Employees
// It reads the employee information and displays those details.
// Error handling is not done here.
func (e Employee) Enroll() {
	fmt.Println("Received the details of Employee")
	fmt.Println("Name          : ", e.Name)
	fmt.Println("Gender        : ", e.Gender)
	fmt.Println("Qualification : ", e.Qualification)
	fmt.Println("Shift Opted   : ", e.Shift)
	fmt.Println("Employee Enrolled!!!")
	return
}

// Submit saves the details submitted by the Employees
// It reads the employee information and displays those details.
// Error handling is not done here.
func (e Employee) Submit() string {
	return e.Name + " submitted details."
}

func main() {
	fmt.Println("Welcome to School")

	// Lets create few student objects
	m_st1 := Student{Name: "Student 1", Grade: "1", Gender: "Male"}
	m_st2 := Student{Name: "Student 2", Grade: "2", Gender: "Female"}
	m_st3 := Student{Name: "Student 3", Grade: "3", Gender: "Male"}
	m_st4 := Student{Name: "Student 4", Grade: "4", Gender: "Female"}
	m_st5 := Student{Name: "Student 5", Grade: "5", Gender: "Male"}

	// Lets create an employees
	m_em1 := Employee{Name: "Employee 1", Gender: "Male", Qualification: "Masters Degree", Shift: 0}
	m_em2 := Employee{Name: "Employee 2", Gender: "Female", Qualification: "Masters Degree", Shift: 0}
	m_em3 := Employee{Name: "Employee 3", Gender: "Male", Qualification: "Bachelors Degree", Shift: 1}
	m_em4 := Employee{Name: "Employee 4", Gender: "Female", Qualification: "Masters Degree", Shift: 1}
	m_em5 := Employee{Name: "Employee 5", Gender: "Male", Qualification: "Bachelors Degree", Shift: 0}

	// Lets collect all the objects in one array
	e := [...]Admitter{m_st1, m_st2, m_st3, m_st4, m_st5, m_em1, m_em2, m_em3, m_em4, m_em5}
	for i, _ := range e {
		e[i].Enroll()
	}

	f := [...]Admitter{m_st1, m_st2, m_em4, m_em5}
	for j, _ := range f {
		fmt.Println(f[j].Submit())
	}

	fmt.Println(" - Bye!")
}

The output now looks like this:

Welcome to School
Received the details of Student
Name    :  Student 1
Grade   :  1
Gender  :  Male
Student Enrolled!!!
Received the details of Student
Name    :  Student 2
Grade   :  2
Gender  :  Female
Student Enrolled!!!
Received the details of Student
Name    :  Student 3
Grade   :  3
Gender  :  Male
Student Enrolled!!!
Received the details of Student
Name    :  Student 4
Grade   :  4
Gender  :  Female
Student Enrolled!!!
Received the details of Student
Name    :  Student 5
Grade   :  5
Gender  :  Male
Student Enrolled!!!
Received the details of Employee
Name          :  Employee 1
Gender        :  Male
Qualification :  Masters Degree
Shift Opted   :  0
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 2
Gender        :  Female
Qualification :  Masters Degree
Shift Opted   :  0
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 3
Gender        :  Male
Qualification :  Bachelors Degree
Shift Opted   :  1
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 4
Gender        :  Female
Qualification :  Masters Degree
Shift Opted   :  1
Employee Enrolled!!!
Received the details of Employee
Name          :  Employee 5
Gender        :  Male
Qualification :  Bachelors Degree
Shift Opted   :  0
Employee Enrolled!!!
Student 1 submitted details.
Student 2 submitted details.
Employee 4 submitted details.
Employee 5 submitted details.
 - Bye!

Thats the advantage of Interfaces, of having to call a single common function for many different objects. Hope the above example has clearly explained how to use the interface in golang. Here comes the next big question, when it should be used?

When interfaces should be used?

Basically, you need to ask yourself “What do these things have in common?”. Once you figure out, then you can program against several objects using one interface. Here are few points when to use interfaces:

  • Interfaces are better suited to situations in which your applications require many possibly unrelated object types to provide certain functionality.
  • Interfaces function to break up the complex designs and clear the dependencies between objects.
  • Interfaces makes your application loosely coupled.
  • Interfaces are easier maintainability, makes your code base more scalable and makes code reuse much more accessible.
  • Interfaces add a plug and play like architecture into your applications.

So as you can see interface based development can make a developer’s life much easier, and our applications much cleaner, maintainable and extensible.

Most of the programmers say who understand the interfaces better.

I don’t see much disadvantages of using interface but here are the two points which you should keep in mind why we should not use interfaces:

  • As per definition Interface has much less restriction, so can’t be restricted.
  • If the interface is not used more than once, then its of no use, just wasting resources.

Naming convention for interfaces?
Go’s convention is

By convention, one-method interfaces are named by the method name plus an -er suffix or similar modification to construct an agent noun: Reader, Writer, Formatter, CloseNotifier etc.

http://golang.org/doc/effective_go.html#interface-names

Generally, the interface is nothing but describing the capabilities, right, so choose clear, meaningful names, making sure you and others understand easily. Here are the few interface names Go has used it, ByteReader, ByteWriter, Formatter, ReadCloser, Quantizer, etc.,. The convention says to use “-er” but its not a rule, also it doesn’t needs to be a Proper English word too, unless the name can help us to understand its meaning. In my above example, there is no such word called “Admitter” but as long as its understandable its okay. Its even good if it doesn’t ends with “-er” when you can’t really make a good naming convention with “-er” suffixed. Here are few example names which golang has used in the interfaces, like Conn, Result, Visitor, FileInfo, Auth, etc.,. But don’t name the method something like “Submitterer”, “Admitterer”, “Readerer”, etc., which is not good convention, avoid doing this.

Hope you enjoyed this, Happy programming!!!