3 ms·
I'm much stricter when it comes to what means immutable. counter = counter + 1 vs counter += 1 Are exactly the same to me. In both cases you bind a
by cies 2y ago
I'm much stricter when it comes to what means immutable.
counter = counter + 1
vs
counter += 1
Are exactly the same to me. In both cases you bind a new value to counter: I don't care much if the value gets updated or new memory is allocated. (sure I want my programs to run fast, but I dont want to be too much worried about it, the compiler/interpreter/runtime should do that "good enough" most of the times)
In the absence of type safety immutability --IMHO-- becomes a bit of a moot point. This is valid Elixir:
x = 10
y = 25
z = x + y
y = "yeahoo"
IO.puts "Sum of #{x} and #{y} is #{z}"
Trying to add another line "z = x + y" to the end, and you have a runtime error.
The "feature" of Elixir that allows scoped rebinding to not affect the outer scope, looks frightening to me. Most of the IDEs I've worked with in the past 15 years warn me of overshadowing, because that easily leads to bugs.
Haskell was already mentioned. There we can see real immutability. Once you say a = 3, you cannot change that later on. Sure sometimes (in many programs this can be limited) you need it, and in those cases there's Haskell's do-notation, which is basically syntactic sugar for overshadowing.
- nuancebydefault 2y ago>Most of the IDEs I've worked with in the past 15 years warn me of overshadowing Most IDEs adapt their rules for warnings to the file type. As i understand it, Elixir leans more to the functional paradigm, so the rules are different. This different paradigm has the pros described in the article. Of course it also has cons. If shadowing is a feature of the language, a feature that is often used, the programmer, who has shifted their thinking to that paradigm, knows that, and a warning is not needed.
- cies 2y agoI'd say that rebinding a value to a variable is similar to shadowing IN THE SAME SCOPE. Pretty much what Haskell does with the do-notation.
- cies 2y agoI find FP and shadowing have nothing to do with eachother (maybe except though Haskell's do-notation)
- nuancebydefault 2y agoYou have a point. Maybe the shadowing is a paradigm on itself, supporting FP. If you know it happens all the time, and you know every var lives in the current scope, all you have to care about is the current scope. Just like in C function-local-vars (which might or not shadow globals) , but then applied to every code block.
- mrkeen 2y ago> Maybe the shadowing is a paradigm on itself, supporting FP. Not really. Shadowing is compiler-warning in Haskell.
- borromakot 2y agoThe point wasn’t to encourage shadowing bindings from a parent scope, only to illustrate that it is not the same thing as mutable references. Whether to, and when to, use rebinding is a different conversation, but in some cases it can lead to subtle bugs just like you described.
- cies 2y agoI still think the difference to me as a programmer is largely semantic (except when the performance has to be considered): "rebinding" or "in-place mutation", in both cases it is a mutable variable to me.
- borromakot 2y agoThere is a guarantee that you have when rebinding is the only option. with rebinding: def thing() do x = 10 do_something(x) # x is 10, non negotiably, it is never not 10 end with mutability def thing() do x = 10 do_something(x) # who knows what x is? Could be anything. end Additionally, because rebinding is a syntactic construct, you can use a linter to detect it: https://hexdocs.pm/credo/Credo.Check.Refactor.VariableRebinding.html https://hexdocs.pm/credo/Credo.Check.Refactor.VariableRebind...
- cies 2y agoI find this a much better example than the example shown in the article. I even find it quite useful when explained like this. Thanks!
- mrkeen 2y ago> Haskell's do-notation, which is basically syntactic sugar for overshadowing. Do-notation does not relate to variable shadowing. It's syntactic sugar over excessive flatmapping / pyramid of doom.