axelson

axelson

Scenic Core Team

Weird/incorrect output from a with statement

This is a question that originated on the Elixir Slack from David Billskog and I have made only minor changes to the module.

Given this module:

defmodule Dummy do
  def execute(x) do
    with var_a <- get_a(x),
         var_b <- get_b(x) do
      IO.inspect(var_a, label: "a")
      IO.inspect(var_b, label: "b")
      IO.inspect({var_a, var_b})

      if var_a != var_b do
        IO.inspect(var_a, label: "a")
        IO.inspect(var_b, label: "b")
        IO.inspect({var_a, var_b})
      end
    end
  end
  defp get_a(x) do
    IO.puts("get a")
    if Enum.any?(x, & &1 == "A"), do: 3, else: 2
    |> IO.inspect(label: "returning a")
  end
  defp get_b(x) do
    IO.puts("get b")
    if Enum.any?(x, & &1 == "B"), do: 2, else: 1
    #|> IO.inspect(label: "returning b")
  end
end

Dummy.execute(["A", "B"])

I get this unexpected output:

$ elixir sample.exs
get a
get b
a: 3
b: 2
{3, 2}
a: 3
b: 1
{3, 1}

Does anyone understand what is happening here? I don’t expect for the value of b to change within the if statement, and I do expect the returning a inspect to be printed. Tested on elixir 1.11.2-otp-23 and erlang 23.0.2.

Marked As Solved

josevalim

josevalim

Creator of Elixir

Thanks for the isolated case. I was able to convert it to Erlang:

-module(dummy).

-compile([no_auto_import]).

-export([execute/1]).

execute(_x@1) ->
    _a@1 = get_a(_x@1),
    _b@1 = get_b(_x@1),
    erlang:display(_b@1),
    case _a@1 /= _b@1 of
        false ->
            nil;
        true ->
            erlang:display(_b@1),
            ok
    end.

get_a(_x@1) ->
    case _x@1 == <<"A">> of
        false ->
            2;
        true ->
            3
    end.

get_b(_x@1) ->
    case _x@1 == <<"A">> of
        false ->
            1;
        true ->
            2
    end.


And I see the same issue. I will open up a bug report.

Done: https://bugs.erlang.org/browse/ERL-1440

Also Liked

blackode

blackode

We can check how the code was developed by using quote do

quote do
  if Enum.any?(x, & &1 == "A"), do: 3, else: 2
  |> IO.inspect(label: "returning a")
end
|> Macro.to_string()
|> IO.puts()

That results to

if(Enum.any?(x, &(&1 == "A"))) do
  3
else
  2 |> IO.inspect(label: "returning a")
end

Which is always true in this case. So, it won’t enter into else

axelson

axelson

Scenic Core Team

I’m still seeing the issue with elixir 1.11.2-otp-23 and erlang 23.1.5

al2o3cr

al2o3cr

Can confirm - Axelson’s example works fine on my machine (OTP23.1 / Elixir 1.11.2) and this one fails.

A colleague tried @LostKobrakai’s example on 22.2.6 / 1.11.1 and it printed 2 three times, as expected…

al2o3cr

al2o3cr

Poked at it a little more. Strange things are afoot - I get different results depending on what’s on a line that never executes (OTP 23.1 / Elixir 1.11.2):

defmodule Dummy do
  def execute(x) do
    with var_a <- get_a(x),
         var_b <- get_b(x) do
      IO.inspect(var_a, label: "a")
      IO.inspect(var_b, label: "b")
      IO.inspect({var_a, var_b})

      if var_a != var_b do
        IO.inspect(var_a, label: "a")
        IO.inspect(var_b, label: "b")
        IO.inspect({var_a, var_b})
      end
    end
  end
  defp get_a(x) do
    IO.puts("get a")
    if Enum.any?(x, & &1 == "A") do
      3
    else
      2 |> IO.inspect(label: "nope")
    end
  end
  defp get_b(x) do
    IO.puts("get b")
    if Enum.any?(x, & &1 == "B"), do: 2, else: 1
  end
end

Dummy.execute(["A", "B"])
# prints
get a
get b
a: 3
b: 2
{3, 2}
a: 3
b: 2
{3, 2}

But commenting out |> IO.inspect(label: "nope") makes it do the {3,1} thing…

EDIT: bonus fact - the 1 has some kind of additional significance, changing it to anything else makes the bug stop happening on my machine.

dbi

dbi

I simplified the example to this and can still reproduce the odd print running macOS Catalina 10.15.7 using Elixir 1.11.2 and Erlang 23.1.5.

defmodule Dummy do
  def execute(x) do
    with a <- get_a(x), b <- get_b(x) do
      IO.inspect(b)
      if a != b do
        IO.inspect(b)
      end
    end
  end
  defp get_a(x) do
    if x == "A", do: 3, else: 2
  end
  defp get_b(x) do
    if x == "A", do: 2, else: 1
  end
end
Dummy.execute("A")
# 2
# 1
# 1

Simplifying it one step furter, replacing if x == "A", do: 3, else: 2 (that will always evaluate to true) into if true, do: 3, else: 2 will fix the unexpected output.

defmodule Dummy do
  def execute(x) do
    with a <- get_a(x), b <- get_b(x) do
      IO.inspect(b)
      if a != b do
        IO.inspect(b)
      end
    end
  end
  defp get_a(x) do
    if true, do: 3, else: 2
  end
  defp get_b(x) do
    if x == "A", do: 2, else: 1
  end
end
Dummy.execute("A")
# 2
# 2
# 2

Where Next?

Popular in Questions Top

lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New
JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod -- where is this set? Thanks.
New
vonH
In asking this question I am more interested about the expressiveness of the language itself and less concerned about the availability of...
New
LegitStack
I’m hoping you guys can give me some general advice and perhaps code examples if you’re feeling up to it. I’m very interested in Elixir,...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
kostonstyle
Hi all I want to have a unix time, from the current time plus 1 hour. DateTime.now + 1 hour How to get it in elixir? Thanks
New
beno
I will often find my self writing things similar to: case some_value do nil -&gt; something() "" -&gt; something() _ -&gt; someth...
New

Other popular topics Top

JakeBecker
TL;DR: I’ve just released an implementation of Microsoft’s IDE-independent Language Server Protocol for Elixir. It adds language support ...
1140 51847 244
New
SoCreat
i’m a new one to elixir which editor can i use vs code? or atom? Thanks! :smiley:
New
gshaw
What is the idiomatic way of matching for not nil in Elixir? E.g., First way: defp halt_if_not_signed_in(conn, signed_in_account) when...
New
axelson
This post is a wiki (feel free to hit the edit button near the bottom right of this post to add your own changes!) This post collects co...
239 45766 226
New
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
New
nsuchy
Hi. I’ve noticed that Windows Powershell has it’s own IEX command and you cannot access Elixir’s IEX due to the conflict. This isn’t a cr...
New
lk-geimfari
What is most correct way to open, read and parse JSON file with poison? For example if we have example.json file in root of some projec...
New
vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
ovidiubadita
Hey all, I discovered Elixir and I love it. I always wanted to learn a functional programming and I intended to go for Haskell, but afte...
New
chrisalley
ExUnit now has describe blocks which is a welcome addition coming from RSpec. In the docs, it states that nested hierarchies of describe ...
New

We're in Beta

About us Mission Statement