To inherit or to include? That is the question

Hi

I’ve been poking around the mailing list looking for
some insight into using inheritance vs module include.
It seems like every time I have a good idea for some
class, I wrangle with this question.

For example:

class AppMaker
def main; ; end
end
class MyApp < AppMaker
end
MyApp.new.main

or

module AppMaker
def main; ; end
end
class MyApp
include AppMaker
end
MyApp.new.main

I cannot see that the two behave that differently.
I’m sure there are some differences. Maybe someone
can help me enumerate them.

Ideally, I would like some set of guidelines to help
me make a choice between these two.

Right now, it’s fuzzy to me which one I should use.

Thanks

···


Jim Freeze

“I may not be totally perfect, but parts of me are excellent.”
– Ashleigh Brilliant

“Jim Freeze” jim@freeze.org schrieb im Newsbeitrag
news:20030404085816.A61099@freeze.org

For example:

class AppMaker
def main; ; end
end
class MyApp < AppMaker
end
MyApp.new.main

or

module AppMaker
def main; ; end
end
class MyApp
include AppMaker
end
MyApp.new.main

I cannot see that the two behave that differently.
I’m sure there are some differences. Maybe someone
can help me enumerate them.

Currently I can’t see why you want to inherit a main function - if it’s
what I guess, then main is very application specific and does not lend
itself easily for inheritance at all.

Ideally, I would like some set of guidelines to help
me make a choice between these two.

Right now, it’s fuzzy to me which one I should use.

The simples rule is that you have to use inheritance if you want to reuse
state. Modules can only provide methods. So, if you have a set of
related methods that can be expected to be used in different classes, put
them together in a module.

You should have a look at the std modules. I think this can give you a
feeling how modules are done.

Regards

robert

For example:

class AppMaker
def main; ; end
end
class MyApp < AppMaker
end
MyApp.new.main

or

module AppMaker
def main; ; end
end
class MyApp
include AppMaker
end
MyApp.new.main

I cannot see that the two behave that differently.

Well, you just do what feels right :slight_smile:

In the case of an application framework, I’d typically make it a Class which
you subclass from (your first example). Your ‘main’ function probably makes
some calls to some methods which don’t actually exist (virtual methods) or
which exist as dummy stubs, which are intended to be overridden in the
subclass. So, subclass MyApp fundamentally is just the App framework
class, but with some more useful behaviour added.

I’d use Module where there is standalone functionality which might be mixed
into any existing class. For example, I have a module which loads Amrita
templates on-demand and keeps them in a class-variable cache. This could be
used in different places, and you might want to use it inside an application
framework:

class MyApp < AppMaker
include MyTemplates
def handle(cgi)

expand(‘login.html’)
end
end

but this type of helper class might be used standalone, or mixed into some
other objects. A Module is more flexible as it doesn’t force you to change
any existing inheritance hierarchy.

But even if you created it as a Class instead of a Module, you could still
use it in that way - by creating an instance of the Class, and then
delegating calls to it.

class MyApp < AppMaker
def initialize
@template_cache = MyTemplates.new # Class not Module
end
def handle(cgi)

@template_cache.expand(‘login.html’)
end
end

I had a flash of enlightenment when I realised that including Modules (into
Classes with ‘include’, or into objects with ‘extend’) is really just a neat
way of implementing the Delegator pattern. Your object keeps all its
existing methods; the module overrides or implements some extra ones, and
delegates everything back to the original object/class.

I’m sure there are some differences. Maybe someone
can help me enumerate them.

I think you’ve enumerated it pretty well in those two examples!

Regards,

Brian.

···

On Fri, Apr 04, 2003 at 10:51:02PM +0900, Jim Freeze wrote:

I’ve been poking around the mailing list looking for
some insight into using inheritance vs module include.
[…]
I cannot see that the two behave that differently.
I’m sure there are some differences. Maybe someone
can help me enumerate them.

Ideally, I would like some set of guidelines to help
me make a choice between these two.

matz already stated that inheritance in Ruby is little more than
implementation reuse… no wonder we can mix modules and classes (no pun
intended) so easily…

So it all comes down to the following:
what’s the difference between an inherited abstract base class and an
included module?

There’s not really that much (if you omit syntactic issues), but here’s
something I can think of now:

batsman@kodos:/tmp$ expand -t2 a.rb
module Foo; def self.bar; puts “Foo.foo” end end
class Bar; def self.bar; puts “Bar.foo” end end

class A < Bar
end

class B
include Foo
end

A.bar
B.bar
batsman@kodos:/tmp$ ruby a.rb
Bar.foo
a.rb:13: undefined method `bar’ for B:Class (NameError)

i.e. there’s no relationship between singleton classes w/ include.

Another thing would be

p B === B.new
p Bar === B.new

true
false

There must be more but I am low on caffeine today :stuck_out_tongue:

Wait for Guy Decoux’s answer :wink:

···

On Fri, Apr 04, 2003 at 10:51:02PM +0900, Jim Freeze wrote:


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Even more amazing was the realization that God has Internet access. I
wonder if He has a full newsfeed?
– Matt Welsh

I’ve been poking around the mailing list looking for
some insight into using inheritance vs module include.
It seems like every time I have a good idea for some
class, I wrangle with this question.

I cannot see that the two behave that differently.
I’m sure there are some differences. Maybe someone
can help me enumerate them.

Ideally, I would like some set of guidelines to help
me make a choice between these two.

Right now, it’s fuzzy to me which one I should use.

The OO hardcore will tell you to differentiate not based on
behavioral differences, but focus on the “what is” question.

If MyApp “ISA” AppMaker, then inherit. If it can do everything an
AppMaker can do (and all those things make sense), inheritance is the
better choice.

If, OTOH, MyApp ! “ISA” AppMaker, but simply needs some of its
behavior, or genuinely in your object model, contains an AppMaker,
then aggregation is the way to go.

If neither work quite right, then maybe your object model is a bit
muddy.

However, if your AppMaker is a “bundle” of behavior and is supposed
to be mixed in and is to be used as part of the
behavior/implementation hierarchy rather than be a piece of the type
hierarchy, then the include/‘require’ solution makes sense. (This
seems to me closer to aggregation than inheritance, but not quite, as
historically aggregation would allow you to “slim” the aggregatee’s
available methods by delegating to it just the methods you want to
expose, where require gets you basically everything, much like
inheritance would.)

That’s not necessarily the most pragmatic answer. [“not necessarily
in ruby” anecdotes follow] Many people I’ve seen will inherit simply
to “get” all the base class’ functionality, when the subclass ! “ISA”
base, just for convenience. I’ve seen that bite backsides a lot too.

Too, in C++, a popular pastime was to factor common functionality
into a base class, simply because with C++'s multiple inheritance,
you could. Always seemed kludgy to me.

But, that is sometimes pragmatic, and for small programs, might save
coding time and be perfectly understandable. That distinction is, of
course, left as an exercise to the reader.

When in doubt, I tend to go the OO purist route. I can always
change later, but I find that I have to refactor less when I do this.
YMMV, of course.

···

Do you Yahoo!?
Yahoo! Tax Center - File online, calculators, forms, and more

Jim Freeze wrote:

Hi

I’ve been poking around the mailing list looking for
some insight into using inheritance vs module include.
It seems like every time I have a good idea for some
class, I wrangle with this question.

Also see http://www.ruby-talk.org/37771 where Paul Brannan explains to
me the difference between multiple module inclusion and standard
multiple inheritance (which, of course, does not exist in Ruby).

···


Jason Voegele
“There is an essential core at the center of each man and woman that
remains unaltered no matter how life’s externals may be transformed
or recombined. But it’s smaller than we think.”
– Gene Wolfe, The Book of the Long Sun

IMO, there are different reasons to use each:

Module

  1. Provides namespace wrapping.
  2. Extends the functionality of a class. Enumerable adds several
    methods to a class; Comparable does the same.
  3. Is not expected to be extended itself.
  4. Exists once and only once, but isn’t “unique” in any meaningful
    sense (like a Singleton class).

Class

  1. Provides namespace wrapping.
  2. Can be extended by children.
  3. May exist more than once, or (if a Singleton), has been limited
    to exist once but exists uniquely.

In many ways, it is an art choosing your choice of encapsulation
methods. If you have a set of related functions that operate on a
provided set of data without configuration information, you may want
a module (e.g., Math); if they operate on a provided set of data
with configuration information or operate on themselves, you may
want a class (e.g., Text::Format).

-austin
– Austin Ziegler, austin@halostatue.ca on 2003.04.04 at 13:40:29

···

On Fri, 4 Apr 2003 22:51:02 +0900, Jim Freeze wrote:

Hi

I’ve been poking around the mailing list looking for some insight
into using inheritance vs module include. It seems like every time
I have a good idea for some class, I wrangle with this question.

Perhaps not, but you probably wanted to inherit all the scaffolding around
it. For example, here is a simple but useful CGI application framework:

require ‘fcgi’
class GUI
def initialize(cgi)
@cgi = cgi
@done_header = false
end

def header(*args)
return if @done_header
puts @cgi.header(*args)
@done_header = true
end

def main: virtual

def self.run
FCGI.each_cgi do |cgi|
begin
app = self.new(cgi)
app.main
rescue Exception => detail
app ? app.header : (puts cgi.header)
print <<EOS

Internal error in #{$0}

Internal error in #{$0}

#{CGI.escapeHTML(detail.message.to_s)} EOS puts "
#{CGI.escapeHTML(detail.backtrace.join(\"\n\"))}
" if detail.backtrace puts "" end end end end

You then create your application like this:

class MyGUI < GUI
def main
header
name = @cgi[‘name’][0]
if name
puts “Hello #{name}”
else
puts “Who are you?”
end
end
end
MyGUI.run

That saves you a lot of work :slight_smile: The superclass ‘GUI’ could have lots of
other helper functions in it which you also might want to inherit.

Regards,

Brian.

···

On Fri, Apr 04, 2003 at 11:39:55PM +0900, Robert Klemme wrote:

Currently I can’t see why you want to inherit a main function - if it’s
what I guess, then main is very application specific and does not lend
itself easily for inheritance at all.

In article b6k4k5$647i1$1@ID-52924.news.dfncis.de,

“Jim Freeze” jim@freeze.org schrieb im Newsbeitrag
news:20030404085816.A61099@freeze.org

For example:

class AppMaker
def main; ; end
end
class MyApp < AppMaker
end
MyApp.new.main

or

module AppMaker
def main; ; end
end
class MyApp
include AppMaker
end
MyApp.new.main

I cannot see that the two behave that differently.
I’m sure there are some differences. Maybe someone
can help me enumerate them.

Currently I can’t see why you want to inherit a main function - if it’s
what I guess, then main is very application specific and does not lend
itself easily for inheritance at all.

Ideally, I would like some set of guidelines to help
me make a choice between these two.

Right now, it’s fuzzy to me which one I should use.

The simples rule is that you have to use inheritance if you want to reuse
state. Modules can only provide methods. So, if you have a set of
related methods that can be expected to be used in different classes, put
them together in a module.

But this isn’t quite true. You can create/manipulate instance variables
withing a modules’s methods:

module Foo
def set_var(v)
@var = v
end
def get_var
@var
end
end

class Bar
include Foo
attr_accessor :var
end

b = Bar.new
b.set_var(42)
puts b.var #-> 42

So, the module Foo was able to introduce some state into the class Bar.

Phil

···

Robert Klemme bob.news@gmx.net wrote:

“Phil Tomson” ptkwt@shell1.aracnet.com schrieb im Newsbeitrag
news:b6kqiu0uka@enews4.newsguy.com

The simples rule is that you have to use inheritance if you want to
reuse
state. Modules can only provide methods. So, if you have a set of
related methods that can be expected to be used in different classes,
put
them together in a module.

But this isn’t quite true. You can create/manipulate instance variables
withing a modules’s methods:

module Foo
def set_var(v)
@var = v
end
def get_var
@var
end
end

class Bar
include Foo
attr_accessor :var
end

b = Bar.new
b.set_var(42)
puts b.var #-> 42

So, the module Foo was able to introduce some state into the class Bar.

Oops! Something learned again. Obviously I misread something. Maybe the
difference then is that a module can’t introduce state on initialization?

robert

???
batsman@kodos:/tmp$ expand -t 2 a.rb
module A
def initialize(*args)
args.each do |a|
puts “Adding i.v. #{a}”
instance_eval “@#{a} = 1”
end
end
end

class B
include A
end

a = B.new(“a”)
puts a.instance_variables
batsman@kodos:/tmp$ ruby a.rb
Adding i.v. a
@a

The more I think about it, the more it seems to me that the following
are the only differences:

  • a module cannot be instantiated
  • there is no relation between the singleton method of a class and that
    of an included module (as opposed to what happens in normal
    inheritance)
  • a module cannot be inherited from :wink:

We can then choose between classes and modules to model different
designs, but as far as the interpreter is concerned these seems to be
the only differences (gotta check the source).

···

On Mon, Apr 07, 2003 at 04:47:25PM +0900, Robert Klemme wrote:

So, the module Foo was able to introduce some state into the class Bar.

Oops! Something learned again. Obviously I misread something. Maybe the
difference then is that a module can’t introduce state on initialization?


_ _

__ __ | | ___ _ __ ___ __ _ _ __
'_ \ / | __/ __| '_ _ \ / ` | ’ \
) | (| | |
__ \ | | | | | (| | | | |
.__/ _,
|_|/| || ||_,|| |_|
Running Debian GNU/Linux Sid (unstable)
batsman dot geo at yahoo dot com

Linux: because a PC is a terrible thing to waste
– ksh@cis.ufl.edu put this on Tshirts in '93