Defining and Implementing Protocols: What You’ll Learn

Welcome. In this unit, you will get your first hands-on look at Elixir protocols. Protocols let you write one API that behaves differently based on the data type, which is Elixir’s way of doing polymorphism. Today, you will define a protocol and implement it for several built-in types, then call it and see dynamic dispatch in action. In later units, we will extend this idea to custom structs and then connect it to behaviors to design larger systems.

Define the Protocol (the Contract)

This defines a protocol named Stringify with one required function, to_string/1. The protocol itself does not implement behavior. It only declares the function signature that all implementations must provide.

By setting @fallback_to_any true, you allow the protocol to look for a default implementation if a specific one isn't found for a given type.

Implement the Protocol for Built-in Types

Each defimpl block ties the Stringify protocol to a specific type:

  • Integer: returns a formatted string with the integer value.
  • List: uses length/1 to report the number of items.
  • Map: uses map_size/1 to report how many keys it has.
  • Any: provides a default behavior for any type that doesn't have a specific implementation.

Key idea: Every implementation must define all functions declared in the protocol. If a type does not have an implementation and you have not provided a fallback for Any, Elixir will raise a Protocol.UndefinedError.

Note: Implementations can live in separate files or apps. Protocol implementations are consolidated at compile time for performance. Keep implementations available at compile time to avoid missing or stale protocol dispatch.

Use the Protocol (Dynamic Dispatch)

Each call routes to the matching implementation:

  • 42 hits the Integer implementation: Integer: 42
  • [1, 2, 3] hits the List implementation: List with 3 items
  • %{...} hits the Map implementation: Map with 2 keys
  • 3.14 (a Float) hits the Any implementation: Fallback: 3.14

This is polymorphism without conditionals. You call the same function, and Elixir picks the right behavior based on the value’s type.

Summary and What’s Next

You defined a protocol, implemented it for Integer, List, Map, and a fallback Any type. You learned that dispatch is by the type of the first argument and that @fallback_to_any allows you to handle unknown types gracefully.

Next, you will practice to lock in the concepts and build confidence. Then we will move on to using protocols with your own structs and, later, connect these ideas to behaviors to design flexible systems.

Sign up
Join the 1M+ learners on CodeSignal
Be a part of our community of 1M+ users who develop and demonstrate their skills on CodeSignal