Sanjibukai

Sanjibukai

Hello everybody,

I just noticed something that I admit I should have been notice way more earlier TBH..
Variables are scoped in ifs, conds, cases (and I bet it’s applicable to any block).

An example with a simplified snippet:

def doing_something do
  a = 1
  ...
  if some_true_condition do
    a = 2
    ...
  end
  IO.inspect(a)  # > Still 1 even if some_true_condition is true
end

Now I’m even surprised of how I didn’t got any bugs so far related to this behavior I wasn’t aware.
Maybe I’ve embraced FP well more than I think (so i’m glad).

But until now I didn’t come across (or maybe I didn’t notice) any resource explaining this behavior.
And it’s a really important behavior!

I searched on hexdocs.pm and looked on almost all the guides pages on elixir-lang and this is the only result I found, a changelog for version 1.3 where the following is stated:

Elixir will now warn if constructs like if , case and friends assign to a variable that is accessed in an outer scope.

And contrary to that there isn’t any warning anymore (on v1.10 btw).

I thought replacing the if construct by assigning from the whole block like so:

a =
  if some_true_condition do
    ...
    2
  end

But in this case we are still changing the value with nil if some_true_condition is actually false instead of doing nothing.

If you happen to have to do something equivalent (changing a value in a block) how do you handle it?
Also if you have any more information about this behavior, I’m interested to learn more.

Thank you!

Showing Posts 1 to 10

kokolegorille

kokolegorille

It is more about scoping than FP…

I would do it like this if needed

a = if ..., do: 2, else: other_value
lud

lud

Remember that you are not changing the value of a. What you are really doing is creating a new variable with the same name (and deleting the old variable).

Sanjibukai

Sanjibukai OP

It is more about scoping than FP…

I meant, FP drastically reduced the usage of ifs.

I would do it like this if needed

a = if ..., do: 2, else: other_value

I was more talking about changing a value or not.
Here with using else you’ll still change the value…

Or do you?
Indeed you can simply affect the variable to itself again:

a = if ..., do: 2, else: a

So, yes this can do the trick.

Thank you for the link too BTW!

Sanjibukai

Sanjibukai OP

Indeed! My bad!
I should have say re-binding the variable..

lud

lud

True, and with that in mind you clearly see that you cannot conditionally rebind it or not.

In the end, instead of

a = if ..., do: 2, else: other_value

You will write the following

a = if ..., do: 2, else: a

But I’ve found this to be a very rare construct, generally hidden by a more complex one.

al2o3cr

al2o3cr

FWIW, I find myself using this with Ecto.Multi when operations should only be done sometimes:

multi =
  Ecto.Multi.new()
  |> Ecto.Multi.insert(:a, some_changeset)
  |> Ecto.Multi.update(:b, some_other_changeset)

multi =
  if control_variable do
    Ecto.Multi.insert(multi, :c, optional_changeset)
  else
    multi
  end
Sanjibukai

Sanjibukai OP

I my case it was also related to a use case with Ecto for a custom validation of a changeset.

Anyway, does anyone know why there is not anymore any warning as it was the case in Elixir 1.3?

NobbZ

NobbZ

Because in 1.7 or 1.8 the “imperative assignment”, which previously issued the warning and changed the value, got removed.

I do consider this a breaking change in elixir, others say the imperative assignment before was a bug that has been fixed with more than enough time of warning.

Sanjibukai

Sanjibukai OP

TIL that there was the “imperative assignment” in Elixir..

So if I correctly understood, now we have what’s a pattern matching, and a variable binding when a variable is on the left hand side (without the pin ^).. But back then there was an other behavior called “imperative assignment”?

al2o3cr

al2o3cr

There’s some nuance to Elixir scoping because what would be “reassignment” in other languages is really more of a “rebinding”:

iex(1)> foo = 123
123
iex(2)> thing = fn -> foo end
#Function<21.126501267/0 in :erl_eval.expr/5>
iex(3)> thing.()
123
iex(4)> foo = 456
456
iex(5)> thing.()
123

The anonymous function in thing captures the value of foo when it’s initially evaluated in the second expression. Subsequent “reassignment” of foo is really rebinding the name, so the anonymous function retains its original reference.

This behavior is intended to be more ergonomic than Erlang, which uses the pattern-matching approach and allows exactly one assignment / binding for a name. In that style, the example above is:

iex(1)> foo1 = 123
123
iex(2)> thing = fn -> foo1 end
#Function<21.126501267/0 in :erl_eval.expr/5>
iex(3)> thing.()
123
iex(4)> foo2 = 456
456
iex(5)> thing.()
123

Written in this style, it’s much more apparent that the second assignment shouldn’t affect the first binding.

Where Next? Top

Trending in Discussions Top

cblavier
Hey there, It’s been more than a year since we started using LiveView as our main UI library and building a whole library of UI componen...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
axelson
Hi there! :wave: @frigidcode and I (but mostly him) have been running an Elixir Book club, we’re almost done with Designing Elixir Syste...
New
achempion
I’ve been using Emacs as my main code editor for more than a two years. It’s a custom build version although I’ve tried doom emacs and sp...
New
budgie
I love Elixir. It’s one of 2 programming languages I’ve ever fallen in love with. But I don’t use it anymore. Serverless was the promis...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
georgeguimaraes
Just published claude-code-elixir, a plugin marketplace for Claude Code with Elixir support. These are the plugins I’ve been using for my...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews