Adding to_string simplifies Elixir code development and debugging

Published on May 17, 2017

Adding to_string simplifies Elixir code development and debugging

    Let's check on an example: we write a service with airports and directions.

    defmodule Airport do
      defstruct [:id, :name]
    end
    defmodule Direction do
      defstruct [:origin, :destination]
      def example do
        madrid = %Airport{id: "MAD", name: "Madrid"}
        riga = %Airport{id: "RIX", name: "Riga"}
        %Direction{origin: riga, destination: madrid}
      end
    end
    

    So far, so good. Well, we ate a cookie, we look, what's next in fat. List of the most popular destinations?



    First, make a small test list and get an unreadable sheet:

    popular = Enum.map(1..5, fn _ -> Direction.example end)
    # =>
    # [%Direction{destination: %Airport{id: "MAD", name: "Madrid"},
    #   origin: %Airport{id: "RIX", name: "Riga"}},
    #  %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
    #   origin: %Airport{id: "RIX", name: "Riga"}},
    #  %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
    #   origin: %Airport{id: "RIX", name: "Riga"}},
    #  %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
    #   origin: %Airport{id: "RIX", name: "Riga"}},
    #  %Direction{destination: %Airport{id: "MAD", name: "Madrid"},
    #   origin: %Airport{id: "RIX", name: "Riga"}}]
    

    Add a pinch of readability:

    defimpl String.Chars, for: Airport do
      def to_string(airport) do
        "#{airport.name} (#{airport.id})"
      end
    end
    defimpl String.Chars, for: Direction do
      def to_string(direction) do
        "#{direction.origin}#{direction.destination}"
      end
    end
    

    And we get a clear neat conclusion:

    Enum.each(popular, fn(x) -> IO.puts(x) end)  
    # =>
    # Riga (RIX) → Madrid (MAD)
    # Riga (RIX) → Madrid (MAD)
    # Riga (RIX) → Madrid (MAD)
    # Riga (RIX) → Madrid (MAD)
    # Riga (RIX) → Madrid (MAD)
    

    Now seriously


    Sometimes during development you need to analyze the contents of variables. The internal representation is accurate, but not always readable. In such cases, you can teach Elixir to translate your structures into strings. To do this, define a function to_stringas part of the protocol implementation String.Chars.

    As an added bonus, interpolation will automatically start working. Without an implementation to_stringfor airports, this would not work:

    "#{direction.origin}#{direction.destination}"
    

    That's all. Readable code!