Into Adventure - Part 1 - Binding and Assignment
Updates
- Fixed issue with incorrect variable being called in a Ruby example 2015-09-24
- Added missing set_sentence method 2015-09-25
- Fixed indentation of Ruby and Elixir code 2015-09-25
The starter
This was a secondary idea while creating the presentation. Wasn’t sure if I would add it to the presentation. But then realized that is a quite important concept.
The difference between binding and assignment didn’t cross my mind until I was forced on FP to live without the latter. Some hybrid FP languages (like F#) allow you to use assignment, but shouldn’t be your default option if you want to actually do proper functional programming.
What is binding?
Binding is assigning some piece of code or data with a name, an identifier. The point of binding is to be able to easily use that piece of code or data inside the scope where the binding is used.
The key points in the previous paragraph are identifier and scope. The former is about being easily able to use that piece of code or data. The latter indicates that the identifier only lives inside the scope where the identifier has been declared.
What is assignment?
Assignment is to change the value of data. The data is changed for the lifetime of the container of the data (that be a record, structure, object or collection).
To reiterate: Is a change for the full lifetime of the entity that you are changing. It is not limited by scope.
The OOP way
As I just mentioned, there is no clear separation on OOP languages between asignment and binding. Both things are mostly conflated into assignment. And then you don’t think of the cases where is clearly binding. Now if you are into the theory of computing, you will already know the difference. But, for all OO programmers that I know personally, there is no difference.
We are going to work through some code to see differences between each other.
Binding through method calls
First is the binding that is a binding, even if you don’t call it that.
Above, what we are doing is, during the duration of the method, we bind 5 to number, and we bind “This is a string” to sentence. Once we leave the method, the names number and sentence dissapear. Yet the data that were representing (5 and This is a string) do still exists, until the MyCallerMethod goes out of scope and they get eliminated by the GC (ok, not completely true regarding their lifetime, but we will leave it simplified like that)
Binding inside a method/class
But you have seen already a different way of binding in that example. Which is the way that you bind inside a method.
That is a binding. We are saying that in any subsequent code on the same scope we can use x instead of 5.
So, if we had:
then when we are using puts x we are saying puts the value of the piece of code/data referenced by x
“Wait”, you will say, “that is an assignment”. And I will say is not. x only refers to 5 on the scope of example. Outside of example, 5 is still data that you can use, but x is no longer a way of referring to that data.
Here is another example to drive the idea home better.
Above we are binding the object MyExample to x, then to y when calling print_value, then to z inside print_value. Once we leave print_value, y and z dissapear. But x and the object do still exists. We are binding inside a scope, y and z in the scope of print_value, x in the global scope.
Assignment inside a method
So the question, is then, how do we do assignment? Remember assigning is changing the value of some data.
So above, we are creating an object of type MyObject and then, inside MyAssignmentMethod I am changing the value of the Sentence property. Unlike the binding done before, which is limited to the scope, we are changing the value here for the life of the object, not the scope of the method.
And here you have the exact reason why OO programmers don’t know/don’t care: Assignment and Binding use the same notation (the = sign)
Another example thsi time in Ruby. We are using the ExampleObject declared in the above Ruby code.
First, we create an ExampleObject outside of the assigner object. We give it a sentence of An Object. Then we pass the object to assigner and then, inside assigner we change the value of the sentence to Another value. Which we can check using outputting the value of the example inside assigner. But now if we look at our example object outside assigner we can see that the value remains changed.
Again, assignment is for the lifetime of the entity.
The FP way
FP works differently. First, the main point of Functional Programming is immutability. Therefore assignment is a no, no from the get-go. Of course, that means that you have to operate differently to achieve the same functionality. Not having assignment means that you can change values. It is not equal to being immutable, as you can mutate without assignment. But is a necessary part of it.
Binding through function calls
This basically looks the same as the OOP counterpart.
On the code above we are declaring a function called myMethod to which we are going to pass a couple of values. During the duration of the function call we are using the names number and sentence instead of the values.
Binding inside a function
But what about binding inside functions?
Again, quite similar to what we have done before.
Assignment inside a function
But what about assignment?. Well, if it is something immutable, you can’t. Which, again, is the default behaviour. Elixir, doesn’t allow you to. Clojure, has no mutable local variables, and special cases for interoperability through the JVM (Ref and Agent). F# allows you to create mutable values, and anything that comes from C# is mutable.
See that F# uses a different symbol (<-) for assignment. There is never confusion. = is binding, and <- is assignment (when allowed).
Elixir, though, no luck. You can’t assign
If you try to execute the above code it will complain the following error
(CompileError) structure.exs:10: cannot invoke remote function card.mana/0 inside match
You can, though, create new structure changing some of the values like so:
Rebinding
Now this is an special case. All OOP languages allows you to rebind a variable that has been declared in method, or, in fact, in an object
Ruby doesn’t allow you to rebind a parameter. But C# allows you to through the use of out parameters.
With the above you can rebind.
FP languages are slightly divided over here. Some don’t allow you to rebind at all, like Erlang. Some others, like Elixir, Clojure and F#, do allow you to rebind, to make code more readable.
Above we are binding x to the value 5, and then we rebind x to the value 7. The idea is that you don’t need to create multiple variables to hold each binding.
Of course, instead of rebinding we could use piping. Which we will see on another post.
Conclusions?
Is interesting the fact that binding and assignment have the same notation in OOP languages. Most fo the time, you don’t care what happens. You are considering the variable rather than the object.
Is important to know where that distinction is necessary (F#), otherwise not sure if it is. I think I need to think a bit more about it.
Go Back to Into Adventure Intro