Refactoring
to
maintainability

Two or more ...


Return to Index

Into Adventure - Part 2 - Chaining

2015-10-12

Fluent Interface or Fluent Style has been defined for some time. It is something specific to OOP due to the way that method calls are being made (you are calling the method on an object). A subset, or standard way of doing Fluent style is through the use of method chaining.

As a C# developer, the first time I found the term Fluent Style was with the introduction of LINQ on .Net 3.5

// C#
class MyTestObject
{
    public String Name {get; set;}
    public int Value {get; set;}
}

class Manipulator
{
    public List<MyTestObject> TestObjects {get; set;}
 
    public MyTestObject DoSomeOperations ()
    {
        this.TestObjects.Where(x => x.Name != "").First(x => x.Value > 5)
    }
}

You can see that upon TestObjects (a List, which inherits from IEnumerable) we do an operation, Where, that returns an IEnumerable, upon which we do another operation, First, that will return a single object.

Of course, method chaining and fluent style have been present from the beginning in C#. Due to the String class being inmutable, you could chain method calls if you wanted to do multiple operations to a string.

public String DoSomething (String originalString)
{
    return originalString.Trim().Replace("a", " ").Replace("d", "e");
}

You can do this on other OO languages

# Ruby
class ThreeDObject
  def initialize(x, y, z)
    @x = x
    @y = y
    @z = z
  end
      
  def translate(x, y, z)
    # we translate the object
    self
  end

  def rotate(x, y, z)
    # we rotate the object
    self
  end

  def scale(x, y, z)
    # we scale the object
    self
  end
end


player = ThreeDObject.new(5,4,3)
player.scale(1,1,1).translate(1,0,0).rotate(90,0,0)

As you can see, the rule that needs to be followed is that you must return the next object (on this case self) that is going to have a method called.

You can even combine returning different objects to chain several method calls.

# Ruby
class Player
  def initialize (weapon)
    @weapon = weapon
  end
  
  def AttackWithWeapon
    @weapon
  end
end

class Weapon
  def initialize (damage)
    @damage = damage
  end

  def getDamage
    @damage
  end
end

sword = Weapon.new(5)
player = Player.new(sword)
puts player.AttackWithWeapon().getDamage()

But what about damaging a monster?

# Ruby
class Monster
  def initialize (life)
    @life = life
  end
  
  def receiveDamage (damage)
    @life = @life - damage
  end
end

monster = Monster.new(10)
monster.receiveDamage(player.AttackWithWeapon().getDamage())

This is where the chain breaks. getDamage() returns an integer, and there is no way to chain that result into monster. This is due to the way that you need to return the object unto which you are going to act next.

This idea of chaining works sligthly different on FP languages.

# Elixir
defmodule Player do
    defstruct weapon: nil
end

defmodule Weapon do
    defstruct damage: 0
end

defmodule Attack do

    def attackWithWeapon do
        weapon = %Weapon{damage: 5}
        player = %Player{weapon: weapon}

        IO.puts player.weapon.damage
    end
end

Attack.attackWithWeapon

Really, what I’m doing here is just accessing members of structures and returning them. If you consider each member like a get property you actually get the same behaviour as with the Ruby code.

But what about that proposition with monster? How do I achieve that?

Enter the pipe operator: |> (on Elixir and F#, Clojure has the reader macros -> and -»)

# Elixir
defmodule Monster do
    defstruct life: 0

    def receiveDamage(damage, monster=%Monster{}) do
         %Monster{monster|life: monster.life-damage}
    end
end

defmodule Demonstration do
    def demo do
        weapon = %Weapon{damage: 5}
		player = %Player{weapon: weapon}
        monster = %Monster{life: 17}
        monster = player.weapon.damage |> Monster.receiveDamage monster
       IO.puts monster.life
    end
end

Demonstration.demo

What the pipe operator is doing in this case is pass the result on the left as the first parameter to the function on the right.

The pipe operator becomes the abilitator of chaining. While in OOP languages you do a call on the return value (the context), on FP languages you pass the return value (the context) as parameter to the next function. With this behaviour, what you can achieve is to chain far more easily.

Looking at the chaining of strings, for example, we get this:

# Elixir
defmodule Chaining do
    def stripchars(str, chars) do
        String.replace str, ~r/"|#{Enum.join(String.split(chars, ""), "|")}"/, ""
    end

    def isAllUppercase(str) do
        upper = (stripchars str, "123456789,") |> String.upcase
        upper |> String.strip |> String.length > 0 && stripchars(str, "1234567890,") == upper
    end
end

(Chaining.isAllUppercase "Is it?") |> IO.puts

Of course, on FP working with lists/sequences is the most natural thing to do.

// F#
type SumOfMultiples(multiples) =

    new () = SumOfMultiples([3;5])

    member this.AccumulateMultiples  upperLimit divisor =
            let maximumMultiplier = (upperLimit - 1) / divisor
            List.map (fun number -> number * divisor) [1..maximumMultiplier] 

    member this.To upperLimit = multiples
                                |> List.map (fun number -> this.AccumulateMultiples upperLimit number)
                                |> List.reduce (fun acc elem -> acc @ elem)
                                |> Set.ofList 
                                |> Set.fold (fun acc number -> acc + number) 0

The above code is from an exercise done on exercism.io

What you see there is that the chaining what it does is make you follow the transformations of your data in the order in which is processed (paraphrasing from a Hacker News commenter). It is quite similar to what you can achieve using LINQ on C# (which operates on IEnumerables).

For FP languages, compared to OOP, though, I think that the biggest difference is the one expressed before: instead of having to return an object to make the next call, the return becomes a parameter to the next call. It allows for more flexibility on chaining calls.

Let’s going to look back at the player/weapon duo from before, but with some more code in it.

defmodule Weapon do
  defstruct max_damage: 0, min_damage: 0, speed: 0

  def do_random_damage(weapon) do
    weapon.max_damage
    :random.seed(:erlang.now)
    value = :random.uniform(weapon.max_damage - weapon.min_damage)
    (value + weapon.min_damage)
  end

  def to_string(weapon) do
    "Weapon speed: #{weapon.speed}"
  end
end

defmodule Player do
  defstruct weapons: nil, damage_done: 0

  def select_quickest_weapon(player = %Player{}) do
    select_quickest_weapon player.weapons
  end

  def select_quickest_weapon([weapon|tail]) do
    select_quickest_weapon tail, weapon
  end
	
  def select_quickest_weapon([weapon = %Weapon{speed: speed1}|tail],  %Weapon{speed: speed2} ) when speed1 < speed2 do
    select_quickest_weapon(tail, weapon)	
  end

  def select_quickest_weapon([_|tail], current) do
    select_quickest_weapon(tail, current)	
  end

  def select_quickest_weapon([], current) do
    current
  end

  def remove_weapon(weapon, player) do
    %Player{player| weapons: (player.weapons -- [weapon])}
  end

  def to_string(player) do
    weapons_string = Enum.map(player.weapons, &(Weapon.to_string(&1)))
    ["Player weapons: "] ++ weapons_string
  end
end

defimpl String.Chars, for: Player do
  def to_string(player) do
    Player.to_string(player)
  end
end

defimpl String.Chars, for: Weapon do
  def to_string(weapon) do
    Weapon.to_string(weapon)
  end
end


defmodule Demonstration do
  def demo do
    weapon_slow = %Weapon{max_damage: 10, min_damage: 1, speed: 5}
    weapon_quick = %Weapon{max_damage: 4, min_damage: 1, speed: 3}
    player = %Player{weapons: [weapon_slow, weapon_quick], damage_done: 0}
    player
    |> Player.select_quickest_weapon
    |> Weapon.do_random_damage
    |> IO.puts
  end
end

Demonstration.demo

defmodule Demonstration2 do
  def demo do
    weapon_slow = %Weapon{max_damage: 10, min_damage: 1, speed: 5}
    weapon_quick = %Weapon{max_damage: 4, min_damage: 1, speed: 3}
    player = %Player{weapons: [weapon_slow, weapon_quick], damage_done: 0}
    updated_player = player
    |> Player.select_quickest_weapon
    |> Player.remove_weapon player
    IO.puts updated_player
  end
end

Demonstration2.demo

On Demonstration.demo we have the line |> Weapon.do_random_damage. On Demonstration2.demo we have the line |> Player.remove_weapon. Because the result of the previous call is passed as parameter, it does ensue that is more easy to change which one is the next call. Trying to achieve the same thing with OO will led to a badly shared interface, most probably.

Go Back to Into Adventure Intro

Conclusions?

Method Chaining is very nice syntactic sugar to create flows that are far more easy and natural to follow. They do make things harder to debug. But their flexibility and power compensates.

References

[1]Wikipedia Fluent Interface back up
[2]Exercism back up


Return to Index

Unless otherwise stated, all posts are my own and not associated with any other particular person or company.

For all code - MIT license
All other text - Creative Commons Attribution-ShareAlike 4.0 International License
Creative Commons BY-SA license image