Elixir check if a variable has been initialized

Viewed 21

I am working on Elixir and having an issue with if/case statement. In a recursive function, I want to check if a value has been previously initialized or not, if not I shall set the value, but I am always getting CompileError:

def func_a() do 
 if {v is undefined} do
  v = 1
 end
...
 func_a()
end

I want v to be set to 1 during the first iteration, during the later iterations, I don't need to run that if statement anymore. I am wondering how to check if v is undefined without causing any error (otherwise it won't compile)? Thank you!

To be specific: I need a counter to be added in a function, and I define the counter like this:

  def get_counter(i \\1) do
    fn -> {i, get_counter(i + 1)} end
  end

In my major function:

def func_a(params) do 
  c = get_counter()
  receive do
     something
  end
  after 
     @timeout -> 
        {v,c} = c.() # increment the counter v
        func_a(params)
  end
end

I am still confused about how could I bypass c = get_counter() during the later iteration of recursion?

3 Answers

In Elixir, a variable does not exist in an uninitialized state, so the pattern you sketched out that would work in many OO languages (e.g. PHP or Node) is invalid in Elixir (or in Erlang). There may be some caveats to this that some of the gurus here may be able to clarify for you, but generally the way that Elixir considers variables are more like "labels" for a value. E.g. you can say "here's this nil value and I'm going to "label" it as x", but you can't say "here's x, and it hasn't been attached to anything yet."

You mentioned iterations: perhaps you can share the specific problem you're working on. In Elixir, the Enum module and its map and reduce functions are far and away the most important ways of iterating on lists of data.

Here are a couple structures/syntaxes that may demonstrate something useful to the concept and what you are trying to do:

defmodule Foo do
  def a(nil) do 
    1
  end

  def a(n) do
    n + 1
  end
end

Foo.a(nil) # 1
Foo.a(1)   # 2

Check out the Elixir Gotchas and Common Issues Wiki on the Elixir Forum.


There is no undefined keyword in Elixir, and no way to check if a variable is defined. If a variable is undefined, the compiler will assume that it's a function call with the () omitted.

Additionally beware that in this pseudo-code:

if {v is undefined} do
 v = 1
end

The value you bind to v is scoped to the if block. It will not be available outside of the if. If you want to conditionally assign to a variable you need to do this:

v =
  if foo do
    bar
  else
    baz
  end

I think the premise of your question is misunderstanding how recursive algorithms work in Elixir. If you want to set v to 1 and then do something with it recursively, you could write something like this:

def func_a(v \\ 1)

def func_a(10), do: IO.puts("Done!")

def func_a(v) do
  IO.puts(v)
  func_a(v + 1)
end

def func_a(v \\ 1) is a function header that says v should default to 1 if not provided.

def func_a(10) is a terminating clause. When v is 10 the function will print Done! and exit.

For all other cases, it will print the value and call itself recursively (it will also never end if v is greater than 10 ).

Output:

1
2
3
4
5
6
7
8
9
Done!

What you are trying to do, is to preserve the state somewhere implicitly. This is impossible in . You have several possibilities to achieve this functionality.

① Pass the value through.

def func_a(params, v)
def func_a(params, nil) do
  v = 1
  func_a(params, v)
end
def func_a(params, v) do
  # v is defined once we are in this clause
  func_a(params, v + 1)
end

② Use the dedicated process to preserve the state.

③ Use persistent_term or counters as

def func_a(params) do
  v = :persistent_term.get(:v, 0)
  v = :persistent_term.put(:v, v + 1)
  func_a(params, v)
end
Related