The with Expression

Understand the usage of the with keyword in Elixir.

We'll cover the following

The with expression serves double duty.

  • First, it allows us to define a local scope for variables. If we need a couple of temporary variables when calculating something, and we don’t want those variables to leak out into the wider scope, we use with.
  • Second, it gives us some control over pattern-matching failures.

The following code finds the values for the _lp user.

content = "Now is the time"

lp = with {:ok, file} = File.open("/etc/passwd"),
         content = IO.read(file,:all), 
         :ok = File.close(file),
         [_, uid, gid] = Regex.run(~r/^lp:.*?:(\.d+):(\d+)/m,content)
      do
        "Group: #{gid}, User: #{uid}" 
      end
IO.puts lp      ###=> Group: 26, User: 26 
IO.puts content   ###=> Now is the time

with and pattern matching

In the above example, the head of the with expression used = for basic pattern matches. If any of these had failed, a MatchError exception would be raised. But perhaps we’d want to handle this case in a more elegant way. That’s where the <- operator comes in. If we use <- instead of = in a with expression, it performs a match. But if it fails, it returns the value that couldn’t be matched.

iex> with [a|_] <- [1,2,3], do: a 
1
iex> with [a|_] <- nil, do: a 
nil

We can use this pattern to let the with in the previous example return nil if the user can’t be found rather than raising an exception.

result = with {:ok, file} = File.open("/etc/passwd"),   
              content = IO.read(file, :all),
              :ok = File.close(file),
              [_, uid, gid] <- Regex.run(~r/^xxx:.*?:(\d+):(\d+)/, content)
         do
              "Group: #{gid}, User: #{uid}" 
         end
IO.puts inspect(result) ###=> nil

In the above lines of code, we’re opening the required file by matching its status ok and then saving all its data in the content variable.

Note: We don’t need to go into details of this code at this stage because we’ll read more about tuples and lists later.

When we try to match the user xxx, Regex.run returns nil because there’s no such user available. This causes the match to fail, and the nil becomes the value of the with.

Get hands-on with 1200+ tech skills courses.