Welcome to Giant Robots Smashing Into Other Giant Robots — a weblog about development, business, design and technology — written by thoughtbot.
do we need that
In Ruby there’s 2 ways to add behavior to a class:
- inheritance
- modules
Now inheritance is the same in Ruby as just about everywhere else.
Modules bring something different to the table that’s not as common in lanugages. Modules are a form of multiple inheritance. A couple languages that provide support for classes and objects do offer multiple inheritance e.g. C++ and lisp’s CLOS.
Let’s take a look at C++.
We’ll take the example of both users and companys having addresses i.e. being addressable.
class DomainObject {
public:
bool save ();
bool update ();
int destroy ();
}
class Address : public DomainObject {
public:
string to_string () {
return this.street + this.city + this.state;
}
private:
string street;
string city;
string state;
}
class Addressable {
public:
vector <Address> get_addresses () {
return this.addresses;
}
private:
vector <Address> addresses; // a vector is a dynamically expanding array
}
class User : public DomainObject, public Addressable {
}
class Company : public DomainObject, public Addressable {
}
void print_addresses (Addressable addressable) {
for (vector<Address>::iterator itr = addressable.get_addresses().begin();
itr != addressable.get_addresses().end();
itr++) {
Address address = (Address) *itr
cout << address->to_string() << endl;
}
}
int main () {
Addressable * user = new User;
Addressable * company = new Company;
print_addresses(user);
print_addresses(company);
// i miss this
delete user;
delete company;
return 0;
}
OK bear with me here.
In the above C++ we see that our User and Company classes both inherit from DomainObject and Addressable (multiple inheritance). An Addressable has many Address s. By inheriting from Addressable, User and Company get that behavior for free (inheriting from DomainObject gives us basic CRUD for free).
Now C++ is a statically typed language i.e. we have to declare the types of all our variables. In the main function I create 2 references, 1 to a new User object and 1 to a new Company object. However we refer to them through the Addressable interface. And via polymorphism, #print_addresses is nice and extendable, as long as you pass it something that inherits from Addressable it works.
Now let’s look at this example in Java/C#.
public class DomainObject {
public boolean save () {}
public boolean update () {}
public boolean destroy () {}
}
public class Address extends DomainObject {
public String getAddress () {
return this.street + this.city + this.state;
}
private String street;
private String city;
private String state;
}
public interface Addressable {
public List getAddresses ();
}
public class User extends DomainObject implements Addressable {
public List getAddresses () {
return this.addresses;
}
private List addresses;
}
public class Company extends DomainObject implements Addressable {
public List getAddresses () {
return this.addresses;
}
private List addresses;
}
public class App {
public static void main (String args[]) {
Addressable user = new User();
Addressable company = new Company();
printAddresses(user);
printAddresses(company);
}
public static void printAddresses (Addressable addressable) {
for (Iterator itr = addressable.getAddresses().iterator();
itr.hasNext();) {
Address address = (Address) itr.next();
System.out.println(address.toString());
}
}
Now Java does NOT support multiple inhertance, only single inheritance. Java did introduce a first-class construct called an interface that can only contain a specification of beahvior and not any implementation of it. And a class in Java can implement any number of interfaces. Unfortunately, this results in us duplicating the logic of the Addressable interface in both the User and Company classes. However, the #printAddresses function is still nice and extendable like in the C++ example, pass in an Addressable and it works.
Let’s look at this in Ruby.
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
module DomainObject def self.included(clazz) clazz.class_eval do def save end def update end def destroy end end end end module Addressable def self.included(clazz) clazz.class_eval do attr_reader :addresses end end end class Address attr_reader :street, :city, :state def to_s street + city + street end end class User include DomainObject include Addressable end class Company include DomainObject include Addressable end def print_addresses(addressable) addressable.addresses.each {|each| puts each} end |
Here we mix in both DomainObject and Addressable into User and Company. Now all #print_addresses cares about is that the object passed in understands #addresses and that the object returned from that message understands #each. Since types no longer matter combined with the ability to simulate multiple inheritance using modules, inheritance is entirely unnecessary in Ruby. You can gain the benefits of multiple inheritance in C++ (shared behavior who’s implementation is in 1 place i.e. DRY) and still write very generic code like #print_addresses.
In Rails there’s no reason the following command:
ruby script/generate model user
Can’t generate the following code instead:
1 2 3 4 5 |
class User include ActiveRecord::Base end |
Provided of course ActiveRecord::Base is now a module.
Java’s lack of multiple inheritance but support for interfaces results in the most explicit code because if I look at a class I can see all its behavior right there, no looking in other files (provided I always used interfaces in Java and never extends). Whereas in C++ and Ruby, when looking at a class you can’t see all its behavior because it may be mixed in by a class or module; you’ll see that a class is using a mixin but you’ll still have to find its file to see what it mixes in. This can be a lot of fun, trying finding where ActiveRecord::Base#has_many is defined in Rails.
Now there is a general backlash against multiple inhertiance usually citing the naming ambiguities that can occur if you inherit from 2 classes that in turn inherit from the same class and the complexity it adds to the language implementation. However, I do not have years of C++ experience using multiple inheritance and this mixin style of programming, so I’m not yet sure on how this effects maintainability.
About this entry
You're reading an entry on GIANT ROBOTS SMASHING INTO OTHER GIANT ROBOTS, the company weblog of thoughtbot, inc.
- Author:
- Jared Carroll
- Published:
- September 5th 10:36 AM
- Updated:
- September 30th 09:57 AM
- Sections:
- Development
thoughtbot is hiring
We are hiring web developers and web designers in both Boston and New York, NY.
What are we up to?
We built Shoulda, an eclectic set of additions to Test::Unit; Paperclip to manage uploaded files without hassle; Jester, a REST/ActiveResource client library written in Javascript, and Squirrel, an enhancement for ActiveRecord's find syntax; — amongst some other projects.

Chad (President) and Jon (CTO) co-authored a technical book titled Pro Active Record: Databases with Ruby and Rails, which explores the ins and outs of the ActiveRecord ruby library. You can buy it today at Amazon.com.
About thoughtbot, inc.
We are a small web application development consulting business, with offices in Boston, MA and New York, NY. If you're looking to find a team for your next web development project or your new web application — get in touch.
7 comments
Jump to comment form