There is a difference between
= when using "with" in Elixir. When you use
<- on a "with" statement, you are pattern-matching the result of the expression.
Let's suppose the code below:
with <- find_user(user_id), :ok <- send_reset_password_email(user) do redirect(conn, ...) end
In the case above, we only get redirected if both expressions return the expected values. If one pattern fails, we will exit the expression and return the failed value.
Now, in case you have a function that you know will always return a valid result, you can use the equal sign.
with products = list_products(), :ok <- send_products_list(products) do redirect(conn, ...) end
In this case, supposing
list_products/0 returns a list, it doesn't matter if it is empty or has results. The next function will handle this, so we don't need to pattern match on a specific condition. But this is the same as
products <- list_products() 🤔.
It starts to make a difference when you want to include a guard clause. When using the equal sign, you can't include guards, so it will always go the "default" way.
with products <- when products !=  list_products(), :ok <- send_products_list(products) do redirect(conn, ...) end
For an expression you don't need to match, the main difference of having it inside the "with" is the scope. The
products variable is contained in the "with", and its value will not leak to the rest of the function even to the “else”.
Another way to write the same expression is by removing the
list_products from the “with”, so we don’t need to worry about arrows 😆.
products = list_products() with :ok <- send_products_list(products) do redirect(conn, ...) end
It’s important to notice that on “For Comprehension” this does not apply. You always need to use the
<- as it is the generator.
A comprehension accepts many generators and filters. for uses the <- operator to extract values from the enumerable on its right side and match them against the pattern on the left. We call them generators: docs