Subscribe for only $15 to access all of our content

#66: Pipe Operator

Elixir 1.6

View source on GitHub


Sign up for our newsletter to get notified when new episodes drop

The pipe operator is a useful tool that makes it simple to chain operations together in a way that’s easy to read. Let’s take a look at how the pipe operator works in Elixir.

I’ll start an iex session. Now let’s say we have some data that’s a lowercase string that can contain an underscore and we want to take this string and transform it so that it’s all uppercase and all underscores replaced with spaces.

If you’ve never used the pipe operator before you may be tempted to write the transformation like this - nesting one function call in the other. Or you can handle the transformation in a series of steps. For example, in our first step we could replace the underscores with spaces. Then we can take our new string and uppercase it.

The pipe operator let’s us write this more succinctly, by letting us “pipe” what’s returned from an expression as the first argument into the subsequent function call. If we wanted to use the pipe to do this transformation we would start with our id and pipe it in as the first argument to String.replace. Notice here that we don’t need to include the first argument - id - when using the pipe operator - Elixir handles that for us. Then our modified string that’s returned would be piped in as the first argument to String.upcase returning our formatted string.

$ iex
> id = "some_text" 
"some_id"
> String.upcase(String.replace(id, "_", " "))
"SOME TEXT"
> step_1 = String.replace(id, "_", " ")
"some text"
> String.upcase(step_1)
"SOME TEXT"
> id |> String.replace("_", " ") |> String.upcase()
"SOME TEXT"

Now that we’ve seen how the pipe operator works, let’s use it to refactor some code.

Here we have a function, that we’ve used in previous episodes of ElixirCasts that fetches the current price data for a cryptocurrency. It’s taking an ID for the cryptocurrency and uppercasing it, building an URL, making an API request to the URL, then getting the body of the response, and parsing the JSON that’s returned. This series of transformations is a great candidate for the pipe operator.

First we’ll take id and pipe it into String.upcase removing the id since Elixir will pass that in for us. The result of that will then get piped into build_url(). Then we’ll update our call the API using HTTPoison.get!. Now we can get the body of the response, removing the response from Map.get, but we’ll want to keep the second argument, :body since only the first is passed in and finally we’ll pipe that response into Jason.decode! to return our parsed data.

lib/teacher.ex

...
def coin_data(id) do
  id
  |> String.upcase()
  |> build_url()
  |> HTTPoison.get!()
  |> Map.get(:body)
  |> Jason.decode!()
end
...

Let’s give this try and make sure it’s working.

We’ll go to the command line and start iex with our project. Then we’ll call our new function with the ID for Bitcoin: “btc”. And great - it worked.

$ iex -S mix
> Teacher.coin_data("btc")
%{
  "_id" => "179bd7dc-72b3-4eee-b373-e719a9489ed9",
  "altCap" => 133508657862.68188,
  "alt_name" => "bitcoin",
  "bitnodesCount" => 9478,
  "btcCap" => 119565018360.75626,
  "btcPrice" => 7475,
  ...
}

Because we’re not working about these intermediate variables, our function flows nicely is and more easy to reason about.