Counter problem - code not working as expected

Hi
Unfortunately, my knowledge of Elixir is not yet complete
Why does the following code not work properly?

defmodule A do
  @x 0
  def b do
    for _ <- 1..5 do
      @x = @x + 1
    end

    IO.inspect(@x)
  end
end

A.b()

Exactly I want the simple Python code below in Elixir

x = 0
for n in range(5):
    x = x + 1
print(n)

Thanks

Module attributes are not mutable at runtime. Also elixir scoping rules don’t allow for a 1:1 copy of the python code. You’ll need to use recursion in some for to calculate your value, e.g. using Enum.reduce.

4 Likes

A general note: you’ll get better help in a forum like this if you post the whole error message (instead of just “this doesn’t work”). In this case, here’s what I get when running the Elixir code above:

warning: this check/guard will always yield the same result
  main.exs:5

** (MatchError) no match of right hand side value: 1
    main.exs:5: anonymous fn/2 in A.b/0
    (elixir 1.12.2) lib/enum.ex:3915: Enum.reduce_range/5
    main.exs:4: A.b/0
    (elixir 1.12.2) lib/code.ex:1261: Code.require_file/2

The key thing to understand to understand these messages is that module attributes like @x are interpolated wherever they appear at compile-time. So that Elixir code looks like this to the compiler:

defmodule A do
  def b do
    for _ <- 1..5 do
      0 = 0 + 1
    end

    IO.inspect(0)
  end
end

A.b()

That’s why the first warning prints: the compiler sees that every term involved in 0 = 0 + 1 is a constant.

At runtime, the BEAM attempts to match 0 and the result of 0 + 1 - and fails with a MatchError, because 0 is not 1. That’s the second message.

5 Likes