Refactoring to maintainability

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.

// C#

public class MyExample
{
    public void MyCallerMethod()
    {
        int myNumber = 5;
        string mySentence = "This is a string";
        MyCalleeMethod(myNumber, mySentence);
    }

    public void MyCalleeMethod(int number, string sentence)
    {
    }
}

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.

## Ruby

x = 5

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:

## Ruby

def example()
  x = 5
  puts x
end

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.

## Ruby

class ExampleObject
  def initialize(sentence)
    @sentence = sentence
  end
  def to_s
    "#{@sentence}"
  end
end

x = MyExample.new "This is a string"

def print_value (y)
  z = y
  puts z
end

print_value x
puts x

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.

// C#
public class MyObject
{
    public MyObject (string sentence)
    {
        Sentence = sentence;
    }

    public string Sentence {get; set;}
}

public class MyExample2
{
    private myObject = new MyObject("This is a string");
	
    public void MyAssignmentMethod()
    {
         myObject.Sentence = "New sentence";
    }
}

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.

## Ruby
class ExampleObject
  def set_sentence(value)
    @sentence = value
  end
end

class TheAssigner
  attr_reader :example

  def add_object(newObject)
    @example = newObject
  end

  def modify_object(value)
    @example.set_sentence value
  end
end

assigner = TheAssigner.new

example = ExampleObject.new "An Object"
puts example

assigner.add_object example

puts assigner.example
assigner.modify_object "Another value"
puts assigner.example

puts example

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.

// F#

let myMethod number sentence =
    printfn "%s %d"sentence number

myMethod 5 "This is it"

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?

let myMethod2 () =
	let x = 5
	printf "%d" x

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.

// C#
public class MyObject
{
    public MyObject (string sentence)
    {
        Sentence = sentence;
    }

    public string Sentence {get; set;}
}
// F#
let x = MyObject "This is it"

x.Sentence <- "This is other"

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

## Elixir
defmodule Card do
    defstruct mana: 0, cost: 0
end

defmodule UseCard do
    card = %Card{}

    def tryToChange do
        IO.puts card.mana
        card.mana = 5
        IO.puts card.mana
    end
	
end

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:

## Elixir

defmodule Card do
    defstruct mana: 0, cost: 0

    def tryToChange(card = %Card{}) do
        IO.puts card.mana
        card5 = %{card | mana: 5}
        IO.puts card5.mana
    end
end

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

class MyExample
    def initialize(sentence)
        @sentence = sentence
    end
    def to_s
        "#{@sentence}"
    end
end

x = MyExample.new "This is a string"

puts x

x = MyExample.new "This is another"

puts x

Ruby doesn’t allow you to rebind a parameter. But C# allows you to through the use of out parameters.

// C#
public class MyObject
{
    public MyObject (string sentence)
    {
        Sentence = sentence;
    }

    public string Sentence {get; set;}
}

public class Rebinder
{
    public void Rebind(out MyObject myObject)
    {
        myObject = new MyObject("This was changed");
    }
}

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.

## Elixir
defmodule Test do
    def myMethod do
        x = 5
        x = 7
    end
end

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