Kurisu
How can I access variable defined in "With" statement from its "else" block?
Hello forum!
I’m trying to retrieve an updated conn, returned in the first line of a “with” statement, when second line failed. But I’m getting some error that says new_conn variable doesn’t exist. In the “do” block it is fine though.
Let me show you what my code looks like:
def some_action(conn, params) do
with {:ok1, some_result, new_conn} <- some_func(conn, params),
{:ok2, another_result} <- another_func(some_result)
do
new_conn |> redirect(to: some_path(conn, :index)) # new_conn is accessible here
else
{:error1, message} -> render(conn, "some_error_template.html")
# new_conn is not accessible here
{:error2, message} -> render(new_conn, "other_error_template.html")
end
end
Please how do you think I could get new_conn in the “else” block?
I have an idea but I’m wondering if it is not bad to use a function such as Tuple.append/2 to ensure the new_conn is present in the matching tuple…
Marked As Solved
peerreynders
You don’t.
You probably ran into this:
You’re building values.
So
iex(1)> fun = fn () ->
...(1)> with a <- 1,
...(1)> {2,_} <- {3,a} do
...(1)> :ok
...(1)> else
...(1)> {_,a} = error ->
...(1)> {:error, error, a}
...(1)> error ->
...(1)> {:error, error}
...(1)> end
...(1)> end
#Function<20.127694169/0 in :erl_eval.expr/5>
iex(2)> fun.()
{:error, {3, 1}, 1}
iex(3)>
So you just have to build the value that contains all the information that you need for the error.
The code in the OP would then look something like this:
def some_action(conn, params) do
with {:ok1, some_result, new_conn} <- some_func(conn, params),
{{:ok2, another_result},_} <- {another_func(some_result), new_conn}
do
new_conn |> redirect(to: some_path(conn, :index)) # new_conn is accessible here
else
{:error1, message} -> render(conn, "some_error_template.html")
{{:error2, message}, new_conn} -> render(new_conn, "other_error_template.html")
end
end
Also Liked
ntalfer
thanks @peerreynders
based on this thread, I ended by creating a kind of accumulator that gathers all results got during the multiple clauses
this more generic solution looks like:
with {{:ok, res1}, acc} <- {fun1(), []},
{{:ok, res2}, acc} <- {fun2(), acc ++ [res1]},
...
{{:ok, resN}, acc} <- {funN(), acc ++ [resN-1]} do
# do some stuff...
else
{error, acc} ->
# error contains the result of funP
# acc contains the results of fun1 to funP-1
# do some other stuff...
end
thanks!
idi527
You can return {:error, conn, message} from your functions.
idi527
If you care about errors, maybe try using a case block?
al2o3cr
The issue is scoping: in the example above, what is res4 bound to when fun2() returns {:error, :nope}?
AFAIK, Elixir expects to be able to determine which bindings are in scope at each point statically at compile-time.








