Learn With Me: Elixir - Temporary Scoping and With (#38)

You can create temporary variables that are only in scope briefly using the with expression. If you define variables using the with expression, those variables are only in scope within that expression and go out of scope after the expression is complete.

Here's an example of opening a file, with the file handle being a temporary variable.

fifth_line = with {:ok, file} = File.open("data.txt") 
do
	read_fifth_line(file)
end

In this example a file is opened and pattern matching causes the file handle to be assigned to the variable file. The fifth line of the file is read and returned from the with expression. As with a function, the last value of the last expression within a with expression is returned and is assigned to the fifth_line variable. The variable file will go of scope when the with expression completes.

Since I am not yet familiar with how the File I/O functions in Elixir work, I'm going to do something much simpler in IEx.

iex> number = with sum = Enum.sum(1..10) do
...>    sum + 1
...> end
56

In IEx I have to put the do on the same line as with, but in source code files, do can go on the next line.

It's also possible to have multiple lines creating temporary variables in the head of the with statement that can use temporary variables from previous lines, like so:

customer_names = with db = Database.open("person_data"),
	customer_table = Database.table(db, "customer")
	customer_record = Database.where(customer_table, fn customer -> customer.age > 18 end) 
do
	customer_record.first_name <> " " <> customer_record.last_name
end

I did not have a real database, and I don't think there is even a Database module, so this is a conceptual example rather than an example that you can run.

The db, customer_table, and customer_record variables are all temporary. They can be used in the other other lines in the with statement header and last until the end causes them to go out of scope.

The expressions in the header of the with expression can use pattern matching and even guard clauses, just like a function header.