In article <m24rnc24xh.fsf / zip.local.thomases.com>,
Dave Thomas  <Dave / PragmaticProgrammer.com> wrote:
>Robert Feldt <feldt / ce.chalmers.se> writes:
>
>> On Fri, 30 Nov 2001, Phil Tomson wrote:
>> 
>> > So I got to thinking that perhaps I could make something like a virtual 
>> > base class where you raise an exception if 'run' isn't defined in the 
>> > inheriting class.  But then I thought, "why bother" - Ruby is dynamic, any 
>> > object which responds to 'run' is going to work.  So perhaps the best way 
>> > of communicating this to users of the framework (a task distributor which 
>> > distrubutes tasks to different clients).  So it seems that 
>> > philosophically, the best way to do it is just to document the required 
>> > (and optoinal interface) for the classes of objects to be distributed.
>> > 
>> I tend to use an "abstract base class" with raise NotImplementedError to
>> document this. Not for Ruby's sake but as documentation. A smart doc tool
>> would parse it out and call the class and interface and mark the method as
>> "virtual" or whatever it should be called.
>
>Would a mixin perhaps be a better flag of this?
>
>  class MyTask
>
>    # We support the framework run interface
>
>    includes Runnable
>
>    ...
>
>  end
>
>
>I don't know, as this isn't a paradigm I'm using right now. But it
>strikes me that it gives you more flexibility here, as it allows
>classes to declare their allegiance to more than one protocol.
>
>As with inheritance, Runnable could be nothing more than an empty
>module, there for documentation only, or it could contain meaningful
>implementations, helper functions, and even defaults for the optional
>functions Phil mentions.

I've thought of this, but I think most of the methods from Runnable would 
be overridden anyway so the only thing it seems to buy me is that I could 
have a 'run' method in runnable that, if not overidden in the class 
Runnable is mixed-into, raises an exception.

What I'll probably end up doing is just doing a test in the class which 
distributes these 'runnable' objects to ensure that the object being 
passed along contains a 'run' method: 

....
unless runnableObj.respond_to(:run)
  raise someException
end 
....


The other issue with the Runnable module mixin idea is that the user of 
this Distributor system has to include the Runnable module in the classes 
which he/she wants to distribute anyway - the amount of documentation 
seems to be the same:

"Make sure you include the Runnable module in your class definitions for 
objects you want to distribute.  Also note that you should create your own 
'run' method in the class you're mixing Runnable into - otherwise you'll 
get an exception"

vs:

"objects you wish to distribute should respond to a 'run' method.  If you 
try to distribute an object which doesn't respond to 'run' an exception 
will be raised in Distributor's send_runnable method."

Actually, the second one seems a little easier to document...

BTW: I actually think this is a great feature - being able to send an 
object of any type so long as it responds to a certain method - of Ruby 
(and dynamic languages in general).  In the dynamic case we rely on 
documentation to inform the programmer on how to use the system.  In a 
static language like C++ we rely on the type system to give us errors at 
compile time (but of course we do, in Ruby-land, have ways of doing 
runtime checking such as with 'respond_to').  The dynamic language allows 
us a lot more flexibility.

Phil