bodhilogic

bodhilogic

Elixir is touted as being a ‘Functional Language’ and the common characteristic of a functional language is that its ‘variables’ are immutable.

Other functional languages allow some tolerance for mutability, as long as some explicit ceremony is employed so that the developer knows he/she is ‘breaking the rules’.

it seems to me that the Pin operator should really be an ‘UnPin’ operator so that allowing a left side to be re-matched to a right side becomes an explicit operation i.e. the left side is immutable unless I use the ‘UnPin’ symbol - “I know that by writing ‘^a’ I am explicitly allowing a state change”.

Does this make sense or do I misunderstand something?

I’m not putting Elixir down - just trying to understand it.

Yes, I have read José’s github posting about why he allows re-matching. I am just thinking that allowing re-matching shouldn’t be the default behavior and that it doesn’t cost much time or effort to type one extra character to allow the re-match.

First 10 of 12 Posts Switch mode

benwilson512

benwilson512

Author of Craft GraphQL APIs in Elixir with Absinthe

Rebinding a variable does not mutate data. If I have:

x = %{foo: 1}
y = x
x = Map.put(x, :bar, 2)

y is still %{foo: 1}. The data itself is completely unchanged. We have shadowed x, but that isn’t the same thing as mutability. Data and bindings to data aren’t the same thing. It can be a difficult thing to see at first for some, but the “tolerance for mutability” you speak of from other functional languages doesn’t even apply here, since mutable data is not a feature available in the VM.

This is perhaps easier to see in a loop:

x = 1
for i <- 1..10 do
  x = i
end

If = were performing a mutation, x would be 10, but in fact it’s still just 1. All that happens is shadowing / rebinding, and that naturally doesn’t work across lexical scopes.

kokolegorille

kokolegorille

In Erlang, this does not work…

$ erl
Erlang/OTP 21 [erts-10.0] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Eshell V10.0  (abort with ^G)
1> A=10.          
10
2> A=11.
** exception error: no match of right hand side value 11

But in Elixir it works

$ iex
Erlang/OTP 21 [erts-10.0] [source] [64-bit] [smp:8:8] [ds:8:8:10] [async-threads:1] [hipe]

Interactive Elixir (1.6.6) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> a=10
10
iex(2)> a=11
11

Because underneath, it’s doing

A0 = 10.
A1 = 11.

You might not like it, because it feels like mutation, but it’s not, it’s rebinding. Just consider this as a syntactic sugar. It’s useful when doing

conn = conn |> apply_some_change()

In the end, it does generate valid bytecode for the BEAM, and immutability is respected.

BTW You might prefer Erlang syntax, but You would lose |> :slight_smile:

dimitarvp

dimitarvp

You can use ETS for mutability if you really really need it (say, if you want a big data structure that must change often with minimal performance penalty; or caches).

The pin operator does not mutate. It allows you to match information stored in a variable instead of it being hardcoded. The official docs have pretty good examples, have you tried them in iex?

The = does not assign per se; it matches a pattern and rebinds if the match is successful (namely the variable is internally now a different variable entirely; using the same name is a syntax sugar, and that variable simply points to a new immutable piece of data now; the old value is discarded). It never assigns, as @benwilson512 mentioned.

cmkarlsson

cmkarlsson

While technically correct I think it leaves the impression that you are mutating, especially for newcomers to the language. If I’d guess this behaviour was put in because of two things:

  1. Principle of least surprise, if you are coming from an imperative language (but quite surprising to an erlang developer)
  2. Because they’ve seen too much code like
A0 = do_something(A),
A1 = do_something_else(A0)

and found it unpleasant.

Personally I to some degree see rebinding with the same variable name as an opportunity to rewrite that piece of code. In erlang the A0..AN variables stick out a bit encouraging you to rewrite. I think the risk of allowing re-binding is that it can potentially make it harder for someone who thinks it is mutability to learn how to think functionally.

dimitarvp

dimitarvp

I sympathize and I was quite shocked when I was learning Elixir, in several places. But the gulf between imperative and functional is big and there is not much we can do about it…

I agree, but IMO it all boils down to the discipline of the programmer in the end. I was using throwaway variables long before I ever heard of functional programming, for example. And then you have people writing an OOP library for Elixir. ¯_(ツ)_/¯

Some mind and brain bending is inevitable while one learns Elixir.

In the end it boils down to how adamant the programmer is about the way they want to do things.

bodhilogic

bodhilogic OP

Fantastic responses!

Thank you all so much.

I suppose I just need to “retrain the brain” from a world of imperative programming to that of functional programming.

I had to go through a similar shift many, many years ago coming from iterative programming to the world of Prolog - you just have to learn to think differently ;).

I suppose a year from now, I’ll look back and laugh at myself for not appreciating the syntactic sugar that José took the time to build into Elixir.

Having said all that, I am really looking forward to exploring Elixir and becoming fluent in a ‘new’ way to program!

axelson

axelson

Scenic Core Team

It would be nice if the pin operator was reversed but that would make the syntax quite cumbersome for some simple cases. Take:

^x = 10 vs x = 10

Also it would not be intuitive how to re-using a variable within a pattern match would work. Would you write {^x, ^x} = {20, 20}?

OvermindDL1

OvermindDL1

Honestly I’d probably have had elixir had two operators, one for assignment and matching with a pin, and another for matching and assigning only to new bindings else use a pin to override. The conflating of matching and the weird rebinding/assigning Elixir does right now is confusing to a lot of people.

So no, it’s not that the pin operator is backwards, it’s great for an ‘assign’ operator, the problem is that there isn’t a dedicated matching operator as well. Could use := for assigning and = for matching, or reverse it, or something else, or whatever. Someone could do it with a library.

michalmuskala

michalmuskala

How would that work in expressions where you bind some variables and match on others? Which operator would you use and why?

Also, what about pattern matching in case or function heads, where you don’t have the operator at all, yet still have the matching/binding behaviour.

sribe

sribe

It seems like you’re confusing mutation with re-binding. They’re not the same. Re-binding does not mutate any data; does not create any change that is visible outside the immediate scope.

Where Next? Top

Trending in Discussions Top

AstonJ
As the title says, please share what you’ve been up to with Elixir. Whether that’s been learning it, looking into it, making stuff with i...
2977 91898 914
New
AstonJ
The obligatory hello world thread! Who are you and where are you from? :stuck_out_tongue:
4616 55835 594
New
byu
@chrismccord : I just saw the Extract AGENTS.md from Phoenix.new into phx.new generator commit to the phoenix project. My initial shotgu...
New
arcanemachine
I was working on an Ecto migration and I needed a timestamp. So, for the nth time, I looked up the different data types for timestamps, a...
New
AstonJ
Just a general thread to post chat/news/info relating to AI/ML stuff that may be relevant for Nx now or in the future. Got anything to sh...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New
type1fool
I just stumbled on a newly redesigned elixir-lang.org. :tada: It looks like @Software_Mansion did the work, and I think it is generally a...
New

Other Trending Topics Top

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
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
ausimian
Emily is an Elixir library that runs Nx computations on Apple’s MLX. Install it as the default Nx backend and Nx, defn, Axon, Nx.Serving,...
New
mudasobwa
While I am working on the Language Agnostic Code Audit SaaS, which uses MetaAST (spoiler: I am expecting it to be in a good shape for ann...
New

We're in Beta

About us Mission Statement