ParsaLabs | Blog

A publication about the web and more.

Polymorphism Through Duck Typing in Ruby

| Comments

A while ago I was doing a fun pet project named “Toy Robot Simulator” in Ruby. You can find the source code && documentation here => github.com/pouya314/ToyRobotSimulator. The simulator accepts 5 commands as valid input, parses the command and takes an appropriate action accordingly. At first, this part was done through an ugly switch statement, which was utilised to make decision about what needs to be done based on user input.

To refactor the code, one possible solution is polymorphism. There are several ways to implement polymorphism including inheritance. But, as I understand it, there is another “preferred” way in Ruby (and other dynamic languages) called duck typing. The idea is to mixin the common behavior (by including a module) omitting the need to create a base class at all. This pattern can be seen in some built-in Ruby classes like Array and Hash, where they both include Enumerable. This, in my opinion, is a true adjustment of behavior at runtime, easily made possible by the dynamic nature of Ruby, so I wanted to give it a try.

Here’s some code snippets to illustrate how it’s done:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
  # common functionality
  module ParsingConcerns
    def preprocess
      puts "I am preprocessing here.."
    end
  end

  class XMLParser
    include ParsingConcerns

    def parse
      puts "parsing xml..."
    end
  end

  class JSONParser
    include ParsingConcerns

    def parse
      puts "parsing json..."
    end
  end

  class GenericParser
    def parse(parser)
      parser.parse
    end
  end

Now you can do:

1
2
3
  parser = GenericParser.new
  parser.parse(XMLParser.new)   # output=> parsing xml...
  parser.parse(JSONParser.new)  # output=> parsing json...

Note that XMLParser and JSONParser do not inherit from GenericParser and get their common functionality from ParsingConcerns module which they both include in their respective classes. Generic parser accepts a parser object and “expects” it to respond to parse method. That’s the essence of duck typing: if it walks like a duck, swims like a duck, quacks like a duck, you can most certainly call it a duck!

Back to the problem at hand, the strategy is to have a GenericParser that takes the command and runs it through the some validations, then dynamically create an object of a more specific type of command and send the parse message to it. This way, the specific parsing (and validation) for each specific command will happen in its own class. From extensibility point of view, with this approach, developers will be able to add a new command by just introducing a new class and encapsulating all parsing and validation code in it, without having to hunt for && update any switch statement. Also, if a subset of commands require a same unique validation, it can be done in a common superclass from which all such commands are inherited. Note, however, that this is slightly different from the standard implementation of duck-typing, i.e. instead of sending the finalized object type to the generic class, I’m letting it decide (dynamically) what type of object it should send the .parse() message to.

Implementation can be found here: https://github.com/pouya314/ToyRobotSimulator/blob/master/lib/robogame/simulator.rb Have a look at the Generic and other Parser classes.

Comments