Traits are somewhat like Abstract Classes in PHP. They’re almost like taping on additional methods onto a class.

trait Meows {
  public function meows() {
    echo 'meow';
  }
}

This Meows trait will add the meowing capability to any class that uses the trait. Let’s remove the meow method from our Cat instance and let the Meows trait do that work:

class Cat {
  use Meows;
}

$cat = new Cat();
$cat->meow();

=> 'meow'

`

Now other classes can use that meowing functionality without having to extend an abstract class:

// did you know that the Mountain Lion is the largest feline that can meow?
class MountainLion {
  use Meows;
}

$mountainLion = new MountainLion();
$mountainLion->meow();

=> 'meow'

Like Abstract Classes they cannot be instantiated on their own:

$meows = new Meow();

=> 'Exception: cannot instantiate Trait'

What’s the difference between Traits and Abstract Classes?

However the biggest difference between Traits and Abstract Classes is that a regular PHP class cannot extend from multiple Abstract Classes:

class Cat extends Animal extends Pet {
  // error error
  // double extension in PHP is not possible!
}

However you can use multiple traits without a problem. Imagine we had another trait, Purrs:

trait Purrs {
  public function purr() {
    echo 'purrrrrr';
  }
}

Now we can use both Meows and Purrs in the same class:

class Cat {
  use Meows, Purrs;
}

$cat = new Cat();
$cat->meow();
$cat->purr();

=> 'meow'
=> 'purrrrrr'

Traits in Ruby

Ruby has this same concept built right into the language. However a Ruby “trait” it’s not a dedicated “type” that you can attach to full classes.

Back in the namespacing section of this series I hinted that Modules were like Traits. It’s true, they’re very much like Traits:

  1. They cannot be instantiated on their own
  2. They can have methods defined for public or private use
  3. They can extend classes
  4. A class can have multiple traits (or modules) attached

With that said, let’s create our first Trait:


module Meows
  def meows
    puts 'meows'
  end
end

Now to use it on our Ruby class, we’ll need to use the keyword include instead of PHP’s use:


class Cat
  include Meows
end

cat = Cat.new
cat.meows

=> 'meows'

It’s just that simple. The include keyword essentially tapes all of the methods available in a Module and attaches them to the class.

Multiple Modules in a Class

Just like PHP’s Traits, we can use multiple Modules in a Class. Let’s make a Ruby equivalent of Purrs:


module Purrs
  def purrs
    puts 'purrrrrr'
  end
end

Now we can attach both Purrs and Meows modules to our Cat class:


class Cat
  include Purrs, Meows
end

cat = Cat.new
cat.purr
cat.meow

=> 'purrrrrr'
=> 'meow'

And there you have it. PHP Trait like functionality in Ruby by using Modules.