Interfaces in Go: Simplified with a silly Analogy

Interfaces in Go: Simplified with a silly Analogy
Photo by Trude Jonsson Stangel / Unsplash

This is how I finally made sense of interfaces in Go. There are countless resources out there, but fails to simplify how to grasp and implement interfaces effectively, atleast for me. While observing my niece one day (toddlers can be surprisingly inspiring!), an analogy clicked in my mind. Let me walk you through it - please bear with me. lol lol

The Analogy

  1. Behavior: "Picking her nose" is a behavior that describes what my niece does.
    • In Go, this is analogous to an interface, which defines a behavior without caring about how it's performed.
  2. Implementation: "How does she pick her nose?" By poking her finger into her nostril.
    • This corresponds to the method implementation—the details of how the behavior is executed.

So far, so good. Let’s dive into some code!

From Analogy to Code

Step 1: Define the Interface
The interface defines the behavior without caring about how it's implemented. Here, the behavior is "picking her nose.":

// Define the NosePicker interface with the behavior
type NosePicker interface {
    PickNose() string // Behavior: Picking nose
}

Step 2: Create a Struct
Now, let's identify who exhibits this behavior. An animal? a person? a fly? A zombieeeee? I ain't sure about Zombiee but in our case, it's a person. Specifically, my niece.

type Person struct {}

Step 3: Implement the Method
Next, we define how my niece performs the behavior:
(On how a behaviour is suppose to get executed.)
So now you are saying this method is going to get executed only be a person.

func (p Person) PickNose() string {
    return "My niece picks her nose by poking her finger into her nostril."
}

Step 4: Use the Interface
We can now create a function that accepts any NosePicker (like my niece, her friends, or anyone else who implements the PickNose behavior):

func ObserveNosePicker(np NosePicker) {
    fmt.Println(np.PickNose())
}

Step 5: Main Function
Finally, let's create an instance of Person and observe the behavior:
Note: Refer this blog to understand what does creating an instance mean?

func main() {
    niece := Person{}
    ObserveNosePicker(niece)
}

Output:

My niece picks her nose by poking her finger into her nostril.

Expanding the Example

Now next thing is to question this behvaior execution could be different to different people. Imagine there are 10 people who have the behaviour of picking their nose but the way they do might vary, while keeping fundamental behaviour same. Example one picks her nose using tissue. Or one picks her nose using Q-tip etc

So, the beauty of interfaces is their flexibility of introducing these. Let's introduce more individuals with unique ways of performing the same behavior.

type Nisha struct{}

func (n Nisha) PickNose() string {
    return "Nisha picks her nose carefully using a tissue."
}

type Kuku struct{}

func (k Kuku) PickNose() string {
    return "Kuku picks his nose with a Q-tip."
}

We can observe their behaviors using the same function:

func main() {
    niece := Person{}
    ObserveNosePicker(niece)

    nisha := Nisha{}
    ObserveNosePicker(nisha)

    kuku := Kuku{}
    ObserveNosePicker(kuku)
}

Output:

My niece picks her nose by poking her finger into her nostril.
Nisha picks her nose carefully using a tissue.
Kuku picks his nose with a Q-tip.

Of course now be imaginative and variablise it and what not.

Key Takeaways

Interfaces: Define the "what" (behavior) without worrying about the "how" (implementation).
Structs: Represent entities that exhibit the behavior.
Methods: Provide specific implementations of the behavior.
Flexibility: Interfaces allow multiple entities to implement the same behavior in their unique way.

Why This Matters?
Think of the interface as a contract: it ensures consistency in behavior while allowing individual implementations. This approach allows flexibility, scalability, and maintainability in your code.

Closing Thought

Sometimes, everyday observations can demystify complex concepts. So next time you're stuck, maybe take a step back and find inspiration in the small, quirky moments around you. Who knew watching a toddler could lead to a clearer understanding of Go interfaces? Hahah.