Protocol Oriented Programming

A while back I was doing a project in Ruby. I knew Ruby very well, all the insides and outs of classes, mixins, singleton classes etc. And yet, I felt something was missing in how I coded in Ruby.

 

I came to the conclusion the reason of my poor Ruby design was my prior experience in statically typed languages. When I came to code in Ruby, I used the same concepts I already knew to build a type hierarchy of classes. But because Ruby is not statically typed, this hierarchy served little purpose.

 

Lets see an example of a ruby code:

def printName(person)
   puts "Name is #{person.name}"
end

For the statically typed mind, this suggest that printName accepts a Person class with a name attribute. However, what it actually accepts is anything with a name method. If other methods of the person argument are used, this adds more constraints on what kind of object can be passed to personName. More arguments mean more constraints.

 

What is important to note is that all these constraints are not on type. They are on a protocol. There is a protocol in printName for how its arguments should behave. There's nothing to do with types.

 

Looking at it from this point of view, we should not design methods to accepts arguments of a certain type, but of a certain behavior. We might change printName to accept a 'nameable' argument instead of person to reflect that. In a statically typed language this would be analogous to define an interface for every bit of behavior (e.g., a Nameable interface to get a name) and then define classes according to what interfaces they implement. Only this would be very verbose and time consuming to do.

 

So if arguments are defined not by type, but by their protocol (behavior). What is the use of classes? For example, this method:

def printNameAndAge(withNameAndAge) 
  puts "Name: #{withNameAndAge.name}, Age: #{withNameAndAge.name}" 
end

 

Can instead be defined as:

def printNameAndAge(name, age)
  puts "Name: #{name}, Age: #{age}"
end

 

The latter versions seems more general. So why use classes (types)?

 

One reason is implementation. If I have several behaviors (methods/functions) working on the same state data, it is easier to group all of it in a class. If I want to reuse code then inheritance is sometimes easier.

 

Another reason is identity. Accepts a 'withNameAndAge' instead of 'name' & 'age', means that the method may use the argument itself as an identifier to the two values 'name' and 'age'.

 

So, when coding in a dynamic language, one should not concentrate on types, but on behaviour. Define what a method expects from its arguments. Classes and inheritance are then used mainly as a way of code reuse and modularity but are less important in themselves.