Inheritance-and-modules

At the end of last week, we discussed inheritance and modules. I needed to review it as not all of it had sunk-in at runtime-lecture. So here goes:

If one of the many purposes of Ruby Classes is to help free us from redunancy by making certain methods available to all instances of that class. Along that line it seems inheritance builds on the notion of “sharing” in that it allows a Class to make its capabilities available to sub-classes and include further specificity and/or additional methods where necessary.

As I researched inheritance up, people liked using taxonomies to help illustrate this. I’ll do the same but instead use plants instead of animals/mammals/etc. The plant kingdom has certain characteristics that hold true for all things defined as plants including such attributes as— they are cellular, they can convert energy from sunlight to food, they can propogate etc.

There are two primary subclasses of plants: seed-bearing and spore-bearing. Both subclasses possess the primary plant kingdom characteristics (cellular, absorb sunlight) but they also possess additional specifics such as being able to have flowers, being able to either absorb water or circulate fluids throughout itself or being of a certain sex or asexual.

So in Ruby:

class Plant
end

class Rose <Plant
end

class Algae < Plant
end

The Rose class and Algae class are “Child” classes that inherit (denoted by <) all characteristics of the “Parent” class Plant. This makes it easy to ascribe further specificity:

class Plant
    def live
        puts "multicellular, can reproduce, absorbs light, circulate or absorb water"
    end
end

class Rose <Plant
    def make_flower
        puts "leaf, stem, roots" 
    end
end


class Moss < Plant
    def produce_spore
        puts "simple, can live on another plant"
    end
end

A Rose and Moss are a type of plant but also have their own specialized things they can do. Its important to note that in Ruby, at least, a Class can only inherit features from one other class.

This brings us to Modules and Mixins. Modules are, according to Ruby docs, a collection of methods and constants. Hmmm. Need more help here. As it turns out, Ruby itself possesses a number of modules in its standard library. A quick example in IRB:

irb> Math.sqrt(2)
=>1.41421
irb> Math::PI
=>3.14159   

The :: operator denotes which module Ruby should use for the value of a constant. If we want to refer to the methods or constants of a module directly without using ::, we can include that module:

irb> include Math   
=>Object
irb> sqrt(2)
=>1.41421
irb> PI
=>3.14159

As mentioned in the Pickaxe, “Modules define a namespace, a sandbox in which your methods and constants can play without having to worry about being stepped on by other methods and constants.” This is one important use of modules.

The other key important use of modules is that, like inheritance, modules allow functionality to be “shared” between classes thereby streamlining the number of times you have to write the same methods. As one person describes,

“mixins are a group of methods not yet attached to any class. They exist in a module and are not useful until included in a class. Once included they are now normal methods of a class.” (source)

So illustrating on the above Class inheritance structure:

module Plant
    def live
        puts "multicellular, can reproduce, absorbs light, circulate or absorb water"
    end
end

class Rose <Plant
    include Plant

    def make_flower
        puts "leaf, stem, roots" 
    end
end


class Moss < Plant
    include Plant

    def produce_spore
        puts "simple, can live on another plant"
    end
end

Methods within a module can either be instance methods or module level methods. In the example above, the module is included within a class, thus the module’s methods are “mixed in” as instance methods and apply to all instances of the Rose and Moss classes. As

Why may modules be a better choice over classes with inheritance?

As this person states: Modules are generally more flexible than superclasses. Modules can be managed at runtime, because include is just regular method call, while superclasses are set in stone as you write your class definitions. Modules are much easier to use and test in isolation than tightly coupled hierachy of classes. You can include as many modules as you like, while you can only have one superclass per class.

Modules can also be applied at the Class level by “extending” within the Class. This would allows the methods within the module to be accessed by other classes. This piece of Avi code from Friday’s Playlister was what had led me to look into inheritance, modules and mixins a little further to begin with:

memorable.rb

module Memorable
  module InstanceMethods
    def initialize
      self.class.all << self
    end
  end

  module ClassMethods
    def self.extended(base)
      base.reset_all
    end

      def reset_all
      @all = [] #still do not quite understand why we don't use @@all here
    end

      def count
      self.all.size
    end

    def all
      @all
    end
  end
end

We see in the partial Artist.rb file below, all the methods in module Findable and ClassMethods specifically in Memorable will be Artist Class methods. I also noted the use of super, whereby Ruby searches upward in the ancestry to find the method initialize so that it doesn’t need to be written here again.

artist.rb

class Artist
  attr_accessor :name
  attr_reader :songs

  extend Memorable::ClassMethods
  include Memorable::InstanceMethods #modules

  extend Findable

  def initialize
    super
    @songs = []
  end
[code omitted]

So the primary difference in usage as I try to apply this in my own code. include applies to Class Instance Methods and extend when the module is to be extended to other classes instead of being included. Access to the module method is done through the class instead of the instance.

This serves as a start in learning about something unique and powerful to Ruby. From the readings it seems that other languages handle inheritance very differently (multiple inheritances etc.,). Furthermore, really cool things happen when we start looking at how, for instance, mixins from Ruby’s standard library (eg, Enumerable, Comparable, or Math) can work with code in the class using it. Looking forward to putting some of this into greater practice going forward.

Resources and other interesting posts on inheritance and modules: 1. http://www.ruby-doc.org/core-1.9.3/Module.html 2. http://www.rubyist.net/~slagell/ruby/modules.html 3. http://ducktypo.blogspot.com/2010/08/why-inheritance-sucks.html 4. http://ruby.about.com/od/beginningruby/a/mixin.htm