Ruby Ruby Foundations Modules Extend and Include: Part 2

Include/extend vs class inheritance

In the example given for using a formatter in both a resume and a cv, is there a particular reason that you would write that as a module rather than including them as methods of class ProfessionalDocuments that both Resume and CV can inherit from? My initial thought is it is more preference. Are there examples where doing this as a superclass would be a poor choice, or wouldn't work? What instances would you prefer to do inheritance over include/extend?

2 Answers

Patrick Metcalfe
PRO
Patrick Metcalfe
Pro Student 7,563 Points

So from breaking down your question, I think your problems revolve around the idea of a module.

A module is different from a class in that it can't be instantiated, so having objects thats don't really change make great modules. This example really helped me: I live, and go to school in Chicago, IL, but last year I went to Chile for the summer. Though I speak spanish, the class I did best in Chile was Math. Why? Because believe it or not sin(30 deg) is the same in Chicago and Santiago. So an object that handles math stuff makes a really great module because no matter where you are in your code, Math.sin(30) will give you the same answer. Now imagine if I had a Person class. Your name is Garrett and mine is Patrick so depending on where we are #name will give a different result, making Person a great class.

Math.sin 30.degrees  # => 0.5
# Inside a method deep in codebase
Math.sin 30.degrees  # => 0.5 # Same Same

patrick = Person.new "Patrick Metcalfe"
garrett = Person.new "Garrett Kocher"
patrick.name  # => Patrick Metcalfe
garrett.name  # => Garrett Kocher

So to answer your question Formatter should work the same no matter where its used–inside a CV class or a Resume class, a FormattedPaper class or even a Person class for some reason. Its like math in Chicago and Chile, it works the same no matter where it is, and thus a module is the best choice. If it were a class, it wouldn't make any sense for Resume and CV to inherit from it. Resume is not a Formatter or a FormattedAttributes, it just uses those functionality. Like how a "Playable Player" is a player who can play(format) but is not a Playable (that makes no sense, its an attribute not a noun). Now theoretically you could do the following:

class FormattedDocument
  extend 'FormattedAttributes'
  include 'Formatter'
end
class Resume < FormattedDocument; end
class CV < FormattedDocument; end

That would be fine, if thats what you meant, but I interpreted your question differently so lmk if that answers your question or not.

David Gross
David Gross
19,443 Points

You could do that and it would work pretty much the same, except you would have to repeat the method process in two different classes. Since you have two classes that are very similar in attributes you can use NameSpacing. Namespacing is a way of bundling logically related objects together. Using Modules are great for this.

What this example was showing is that you can use NameSpacing in the Module to make your code DRY so you do not have to repeat yourself as much.

remember Include makes the method available to an instance of a class. Extend makes the method available to the class itself.