On Fri, Apr 04, 2003 at 10:51:02PM +0900, Jim Freeze wrote:
> For example:
> 
>   class AppMaker
>     def main; <stuff>; end
>   end
>   class MyApp < AppMaker
>   end
>   MyApp.new.main
> 
> or
> 
>   module AppMaker
>     def main; <stuff>; 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 :-)

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.