# OOP in Go: Interfaces

In the last article, we discussed Go structs, and how they can be used to mimic key OOP concepts like Encapsulation, Abstraction and Inheritance.

A Go interface is a collection of method signatures that define behaviors. An interface is defined using the `type` keyword followed by the name of the new type and the keyword `interface`.

```go
type Ethnicity interface {
	IsAsian() bool
	IsIndian() bool
}
```

In the above example, we define an interface type `Ethnicity` with method signature IsAsian() bool & IsIndian() bool. Any type that has a method with the same signatures is said to implement the interface.

Let us declare a Person struct, and implement IsAsian() and IsIndian() methods with the same arguments and return types.

```go
type Person struct {
	name      string
	country   string
	continent string
}

type Employee struct {
	Person
	salary int
}

func (p Person) IsAsian() bool {
	return p.continent == "Asia"
}

func (p Person) IsIndian() bool {
	return p.country == "India"
}

func main(){
    p := Person{name: "John", country: "India", continent: "Asia"}
    c.IsAsian()
    c.IsIndian()
}
```

Since type `Person` has methods(receiver functions) with the same name and similar return types as defined in the `Ethnicity` interface, it implements the `Ethnicity` interface.

We could also implement the interface by simply declaring a `Person` variable and assigning it to an `Ethnicity` variable, like so:

```go
func main() {
    p := Person{name: "John", country: "India", continent: "Asia"}
	var e Ethnicity = p
	e.IsAsian()
	e.IsIndian()
}
```

Go also allows the embedding of interfaces in structs, which can be helpful in inheriting behaviors and defining new structs with additional behaviors.

```go
type Person struct {
	name      string
    age       int
    netIncome int
	country   string
	continent string
    Ethnicity
}

type WealthManager interface{
    NetWorth() int
    IsWealthy() bool
}

type SuperRich struct{
    Person
    WealthManager
}

func (p Person) NetWorth() int {
	return p.netIncome - p.debt
}

func (p Person) IsWealthy() bool {
	return p.NetWorth() > 1
}

func (s SuperRich) IsSuperRich() {
	fmt.Printf("%v is from %v and, is super rich with a networth of %v", s.Person.name, s.Person.Country, s.Person.NetWorth())
}

func main() {
	fmt.Println("Hello World!")
	p := Person{name: "John", age: 30, netIncome: 50000, debt: 10000, country: "India", continent: "Asia"}
	var isSuperRich SuperRich = SuperRich{Person: p, WealthManager: p}
	isSuperRich.IsSuperRich()
}
```

Here, we have `Person` implementing the `WealthManger` interface by having two receiver functions IsWealthy() and NetWorth().

The `SuperRich` struct combines the properties and behaviors of `Person` and the `WealthManager`, and has additional behavior in the form of `IsSuperRich()` method.

In the main function, we have the isSuperRich variable, where we assign new `Person` p twice. We can assign p to `WealthManager` as the `Person` struct implements the `WealthManager` interface.

Interfaces with no method signatures are not bound to any behavior and hence can hold values of any type. This property allows us to achieve Polymorphism.

```go
type x interface{}
x = "hello"
fmt.Println(x)

x = 42
fmt.Println(x)

x = true
fmt.Println(x)
```

Hence, we can see that interfaces in Go can allow us to mimic OOP properties like Inheritance using nesting and Polymorphism using empty interfaces. Interfaces are used to define behaviors that a type must implement. This allows functions to accept any type that implements the interface, making the code more flexible and easier to maintain.

In the upcoming article, we shall discuss receiver functions in Go.
