Binding vs Assignment - ruby

I've read a number of articles on the difference between assignment and binding, but it hasn't clicked yet (specifically in the context of an imperative language vs one without mutation).
I asked in IRC, and someone mentioned these 2 examples illustrate the difference, but then I had to go and I didn't see the full explanation.
Can someone please explain how/why this works in a detailed way, to help illustrate the difference?
Ruby
x = 1; f = lambda { x }; x = 2; f.call
#=> 2
Elixir
x = 1; f = fn -> x end; x = 2; f.()
#=> 1

I've heard this explanation before and it seems pretty good:
You can think of binding as a label on a suitcase, and assignment as a
suitcase.
In other languages, where you have assignment, it is more like putting a value in a suitcase. You actually change value that is in the suitcase and put in a different value.
If you have a suitcase with a value in it, in Elixir, you put a label on it. You can change the label, but the value in the suitcase is still the same.
So, for example with:
iex(1)> x = 1
iex(2)> f = fn -> x end
iex(3)> x = 2
iex(4)> f.()
1
You have a suitcase with 1 in it and you label it x.
Then you say, "Here, Mr. Function, I want you to tell me what is in this suitcase when I call you."
Then, you take the label off of the suitcase with 1 in it and put it on another suitcase with 2 in it.
Then you say "Hey, Mr. Function, what is in that suitcase?"
He will say "1", because the suitcase hasn't changed. Although, you have taken your label off of it and put it on a different suitcase.

After a while, I came up with the answer that is probably the best explanation of the difference between “binding” and “assignment”; it has nothing in common with what I have written in another answer, hence it’s posted as a separate answer.
In any functional language, where everything is immutable, there is no meaningful difference between terms “binding” and “assignment.” One might call it either way; the common pattern is to use the word “binding,“ explicitly denoting that it’s a value bound to a variable. In Erlang, for instance, one can not rebound a variable. In Elixir this is possible (why, for God’s sake, José, what for?)
Consider the following example in Elixir:
iex> x = 1
iex> 1 = x
The above is perfectly valid Elixir code. It is evident, one cannot assign anything to one. It is neither assignment nor binding. It is matching. That is how = is treated in Elixir (and in Erlang): a = b fails if both are bound to different values; it returns RHO if they match; it binds LHO to RHO if LHO is not bound yet.
In Ruby it differs. There is a significant difference between assignment (copying the content,) and binding (making a reference.)

Elixir vs Ruby might not be the best contrast for this. In Elixir, we can readily "re-assign" the value of a previously assigned named variable. The two anonymous-function examples you provided demonstrate the difference in how the two languages assign local variables in them. In Ruby, the variable, meaning the memory reference, is assigned, which is why when we change it, the anonymous function returns the current value stored in that memory-reference. While in Elixir, the value of the variable at the time the anonymous function is defined (rather than the memory reference) is copied and stored as the local variable.
In Erlang, Elixir's "parent" language, however, variables as a rule are "bound." Once you've declared the value for the variable named X, you are not allowed to alter it for the remainder of the program and any needed alterations would need to be stored in new named variables. (There is a way to reassign a named variable in Erlang but it is not the custom.)

Binding refers to particular concept used in expression-based languages that may seem foreign if you're used to statement-based languages. I'll use an ML-style example to demonstrate:
let x = 3 in
let y = 5 in
x + y
val it : int = 8
The let... in syntax used here demonstrates that the binding let x = 3 is scoped only to the expression following the in. Likewise, the binding let y = 5 is only scoped to the expression x + y, such that, if we consider another example:
let x = 3 in
let f () =
x + 5
let x = 4 in
f()
val it : int = 8
The result is still 8, even though we have the binding let x = 4 above the call to f(). This is because f itself was bound in the scope of the binding let x = 3.
Assignment in statement-based languages is different, because the variables being assigned are not scoped to a particular expression, they are effectively 'global' for whatever block of code they're in, so reassigning the value of a variable changes the result of an evaluation that uses the same variable.

The easiest way to understand the difference, would be to compare the AST that is used by the language interpreter/compiler to produce machine-/byte-code.
Let’s start with ruby. Ruby does not provide the AST viewer out of the box, so I will use RubyParser gem for that:
> require 'ruby_parser'
> RubyParser.new.parse("x = 1; f = -> {x}; x = 2; f.()").inspect
#=> "s(:block, s(:lasgn, :x, s(:lit, 1)),
# s(:lasgn, :f, s(:iter, s(:call, nil, :lambda), 0, s(:lvar, :x))),
# s(:lasgn, :x, s(:lit, 2)), s(:call, s(:lvar, :f), :call))"
The thing we are looking for is the latest node in the second line: there is x variable inside the proc. In other words, ruby expects the bound variable there, named x. At the time the proc is evaluated, x has a value of 2. Hence the the proc returns 2.
Let’s now check Elixir.
iex|1 ▶ quote do
...|1 ▶ x = 1
...|1 ▶ f = fn -> x end
...|1 ▶ x = 2
...|1 ▶ f.()
...|1 ▶ end
#⇒ {:__block__, [],
# [
# {:=, [], [{:x, [], Elixir}, 1]},
# {:=, [], [{:f, [], Elixir}, {:fn, [], [{:->, [], [[], {:x, [], Elixir}]}]}]},
# {:=, [], [{:x, [], Elixir}, 2]},
# {{:., [], [{:f, [], Elixir}]}, [], []}
# ]}
Last node in the second line is ours. It still contains x, but during a compilation stage this x will be evaluated to it’s currently assigned value. That said, fn -> not_x end will result in compilation error, while in ruby there could be literally anything inside a proc body, since it’ll be evaluated when called.
In other words, Ruby uses a current caller’s context to evaluate proc, while Elixir uses a closure. It grabs the context it encountered the function definition and uses it to resolve all the local variables.

Related

Ruby: Idiom for "create and increment"

I am looking for a concise way to deal with the following situation: Given a variable (in practince, an instance variable in a class, though I don't think this matters here), which is known to be either nil or hold some Integer. If it is an Integer, the variable should be incremented. If it is nil, it should be initialized with 1.
These are obvious solutions to this, taking #counter as the variable to deal with:
# Separate the cases into two statements
#counter ||= 0
#counter += 1
or
# Separate the cases into one conditional
#counter = #counter ? (#counter + 1) : 1
I don't like these solutions because they require to repeat the name of the variable. The following attempt failed:
# Does not work
(#counter ||= 0) += 1
This can't be done, because the result of the assignment operators is not an lvalue, though the actual error message is a bit obscure. In this case, you get the error _unexpected tOP_ASGN, expecting end_.
Is there a good idiom to code my problem, or do I have to stick with one of my clumsy solutions?
The question is clear:
A variable is known to hold nil or an integer. If nil the variable is to be set equal to 1, else it is to be set equal to its value plus 1.
What is the best way to implement this in Ruby?
First, two points.
The question states, "If it is nil, it should be initialized with 1.". This contradicts the statement that the variable is known to be nil or an integer, meaning that it has already been initialized, or more accurately, defined. In the case of an instance variable, this distinction is irrelevant as Ruby initializes undefined instance variables to nil when they are referenced as rvalues. It's an important distinction for local variables, however, as an exception is raised when an undefined local variable is referenced as an rvalue.
The comments largely address situations where the variable holds an object other than nil or an integer. They are therefore irrelevant. If the OP wishes to broaden the question to allow the variable to hold objects other than nil or an integer (an array or hash, for example), a separate question should be asked.
What criteria should be used in deciding what code is best? Of the various possibilities that have been mentioned, I do not see important differences in efficiency. Assuming that to be the case, or that relative efficiency is not important in the application, we are left with readability (and by extension, maintainability) as the sole criterion. If x equals nil or an integer, or is an undefined instance variable, perhaps the clearest code is the following:
x = 0 if x.nil?
x += 1
or
x = x.nil? ? 1 : x+1
Ever-so-slightly less readable:
x = (x || 0) + 1
and one step behind that:
x = x.to_i + 1
which requires the reader to know that nil.to_i #=> 0.
The OP may regard these solutions as "clumsy", but I think they are all beautiful.
Can an expression be written that references x but once? I can't think of a way and one has not been suggested in the comments, so if there is a way (doubtful, I believe) it probably would not meet the test for readability.
Consider now the case where the local variable x may not have been defined. In that case we might write:
x = (defined?(x) ? (x || 0) : 0) + 1
defined? is a Ruby keyword.

What is the difference of immutable and mutable variables?

I have read almost every definition of immutable/mutable variables on the internet but as a beginner I just do not grasp it fully so I was wondering if someone could really explain it in layman terms.
Immutable variables (or objects) in any programming language is what I understand when you cannot change the value of that variable after it has been assigned a value. For example, I am using the Haskell programming language, and I write:
let x = 5
Since Haskell has immutable variables, x can never have any other value than 5. So if I after that line of code write:
x = 2
I have in fact not changed the value of x but made a new variable with the same name, which will now be the one that is referenced when I call x, so after both lines of code I can only reach an x with the value of 2.
But what is a mutable variable then, and what programming languages have it? This is where it gets foggy for me. Because when people say mutable variable, they are obviously referring to a variable or object which value you can indeed change after it has been assigned an initial value.
Does this mean that if you have a mutable variable you actually manipulate that place in the computers memory for that variable, and in case of immutable variable you cannot manipulate that place in the computers memory or what?
I don't know how to explain my question any further, as I said, I understand that mutable = can change value of variable after initial value assignment, immutable = cannot. I get the definition. But I don't understand what it actually means in terms of what is going on "behind the scenes". I guess I am looking for easy examples on actual mutable variables.
This has nothing to do with immutability
let x = 5
x = 2
This is reassignment and definitely not allowed in Haskell
First let's look at a regular let assignment
Prelude> let x = 5 in x
5
it :: Num a => a
You can bind x using let, and rebind a new x in a nested let – this effectively shadows the outer x
Prelude> let x = 5 in let x = 2 in x
2
it :: Num a => a
Remember a let is basically a lambda
Prelude> (\x -> x) 5
5
it :: Num a => a
And of course a lambda can return a lambda; illustrates shadowing agian
Prelude> (\x -> (\x -> x)) 5 2
2
it :: Num a => a
I believe a shorthand answer to your question would be that a Mutable variable that holds a value that you would later want to be adjusted.
Depending on the language you're using is its method.
In Kotlin val and var are used to declare variables.
val is a constant while var is adjustable.
Mutable respectively immutable does not concern the variables but the values. Note: one also says the type is (im-)mutable.
For instance if the value is of an immutable type StudentCard, with fields ID and Name, then after creation the fields no longer can be changed. On a name change the student card must be reissued, a new StudentCard must be created.
A more elementary immutable type is String in java. Assigning the same value to two variables is no problem as one variable may not change the shared value. Sharing a mutable value could be dangerous.
A commont mutable type is the array in java and others. Sharing an array, say storing an array parameter in a field, risks that somewhere else the array content is changed inadvertently changing your field.

Why variables setted inside Enum.each is not saved?

I'm trying to set a value to a variable inside a function in Enum.each, but at the end of loop, variable is empty and I don't know exactly why this behaviour.
Code:
base = "master"
candidates = ["stream", "pigeons", "maters"]
return = []
Enum.each(candidates, fn candidate ->
cond do
String.length(base) == String.length(candidate) ->
return = return ++ [candidate]
true ->
true
end
end)
IO.inspect return
At this example, return is expected to be ["stream", "maters"], but instead, it is only an empty list: []
My question is why this happens.
When dealing with languages like Elixir, it is better to think in terms of "values" and "names" instead of "variables".
The reason you cannot do what you want is that Elixir has "lexical scoping".
When you assign to a "variable", you create a new value in the inner scope. You never change the "value" of a "name" defined in the outer scope.
(you probably can get what you want with Enum.filter/2, but I'm guessing this is just an illustrative example)
EDIT:
As of today, Elixir will allow you to write something like this:
if condition_that_evals_to_false do
x = 1
else
x = 2
end
IO.inspect x # => 2
```
But this will be deprecated in Elixir 1.3
Any reason why you don't just filter?
Anyways it seems like you're trying to mutate the value of return which is not possible with Elixir.
base = "master"
candidates = ["stream", "pigeon", "maters"]
result = Enum.filter(candidates, fn(candidate) ->
length(candidate) == length(base)
end
IO.inspect result
Edit: I'd also like to add that based on your logic, all of the candidates would be returned
Not sure, since I've never worked with the language, but a couple things spring to mind:
String.length(base) == String.length(candidate) can be equivalent to true, which is already a pattern in your set.
It could also be a scope issue with the return variable. It could be that the local return is hiding the global return. You could check this by outputting return every iteration. Each iteration the return should contain a single entry.
This is a bug. From Elixir's documentation:
Note: due to a bug in the 0.12.x series, cond‘s conditions actually
leak bindings to the surrounding scope. This should be fixed in
0.13.1.
You should use filtering like #{Christopher Yammine} suggested.

Ruby: evaluate string with dynamic binding of variables

I have a database of "formulas" stored as strings. Let's assume for simplicity, that each formula contains 2 variables denoted by a and b, and that the formulas are all wellformed and it is ensured that it consists only of characters from the set ()ab+-*.
At runtime, formulas are fetched from this database, and from another source, numeric values for a and b are fetched, and the formulas are evaluated. The evaluation can be programmed like this:
# This is how it works right now
formula = fetch_formula(....)
a = fetch_left_arg(....)
b = fetch_right_arg(....)
result = eval(formula)
This design works, but I'm not entirely happy with it. It requires that my program names the free variables exactly the same as they are named in the formula, which is ugly.
If my "formula" would not be a string, but a Proc object or Lambda which accepts two parameters, I could do something like
# No explicitly named variables
result = fetch_proc(...).call(fetch_left_arg(....),fetch_right_arg(....))
but unfortunately, the formulas have to be strings.
I tried to experiment in the following way: What if the method, which fetches the formula from the database, would wrap the string into something, which behaves like a block, and where I could pass parameters to it?
# This does not work of course, but maybe you get the idea:
block_string = "|a,b| #{fetch_formula(....)}"
Of course I can't eval such a block_string, but is there something similar which I could use? I know that instance_eval can pass parameters, but what object should I apply it to? So this is perhaps not an option either....
This is very nasty approach, but for simple formulas you’ve mentioned it should work:
▶ formula = 'a + b'
▶ vars = formula.scan(/[a-z]+/).uniq.join(',') # getting vars names
#⇒ "a,b"
▶ pr = eval("proc { |#{vars}| #{formula} }") # preparing proc
▶ pr.call 3, 5
#⇒ 8
Here we rely on the fact, that parameters are passed to the proc in the same order, as they appear in the formula.
If I get your question correctly, it is something that I have done recently, and is fairly easy. Given a string:
s = "{|x, y| x + y}"
You can create a proc by doing:
eval("Proc.new#{s}")
One way to avoid creating the variables in the local scope could be to use a Binding:
bind = binding
formula = fetch_formula(....)
bind.local_variable_set :a, fetch_left_arg(....)
bind.local_variable_set :b, fetch_right_arg(....)
result = bind.eval(formula)
The variables a and b now only exist in the binding, and do not pollute the rest of your code.
You can create a lambda from string, as shown below:
formula = "a + b"
lambda_template = "->(a,b) { %s }"
formula_lambda = eval(lambda_template % formula)
p formula_lambda.call(1,2)
#=> 3

Why isn't `method=` treated the same as any other method?

Consider the following code snippet:
class Example
def my_attr=(value)
#_my_attr = value
#_my_attr * 3
end
end
I expect the expression Example.new.my_attr = 5 to return 15, but that turns out to be wrong. The original return value is always returned, even when I call the = method explicitly:
Example.new.my_attr = 5 # => 5
Example.new.my_attr=(5) # => 5
How and why does Ruby do this? Does Ruby treat methods that end in = specially, or is it some other mechanism? I guess this precludes chaining on return values of = methods, right? Is there a way to make Ruby behave differently, or is this just how it is?
Update: Credit to #jeffgran for this:
Example.new.send(:my_attr=, 5) # => 15
This is a workaround, but on another level even more perplexing, since that would mean send is clearly not always equivalent in behavior to calling a method directly.
This is how assignment works; the return value is ignored, and the result of an assignment expression is always the right-hand value. This is a fundamental feature of Ruby's grammar. left-hand side = right-hand side will always evaluate to right-hand side, regardless of whether left hand side is a variable (x), a method (object.x), a constant (X) or any expression.
Source: Programming Languages | Ruby
IPA Ruby Standardization WG Draft, 11.4.2.2.5, Single method assignments
Consider chaining of assignments, x = y = 3.
For this to work correctly, the result of y = 3 must be 3, regardless of the actual value returned by the y= method. x = y = 3 is meant to read as y = 3; x = 3, not as y = 3; x = y which is what would be implied if the return value from y= was treated as the result of y = 3.
Or consider all the other places assignment can be used. Sometimes, instead of this...
obj.x = getExpensiveThing()
if obj.x
...
... we write this ...
if obj.x = getExpensiveThing()
This couldn't work if the result of obj.x = ... could be any arbitrary thing, but we know it will work because the result of obj.x = y is always y.
Update
A comment on the question states:
Interesting, I wasn't aware of this scenario. It seems that method= returns whatever input is given...
No, it's an important distinction to make. This has nothing to do with the return value of method assignment, and it definitely does not "return whatever input is given", it returns whatever you tell it to return.
The whole point is that the return value is ignored by the grammar of the language; assignment doesn't evaluate to the return value of the attr= method, but the return value still exists as evidenced by the question itself: Example.new.send(:my_attr=, 5) # => 15. This works because it is not assignment. You're side-stepping that part of the Ruby language.
Update again
To be clear: x and y in my examples shouldn't be interpreted as literal Ruby variables, they are place holders for any valid left-hand side of an assignment. x or y could be any expression: a, obj.a, CONSTANT_A, Something::a, #instance_a, it's all the same. The value of assignment is always the right-hand side.

Resources