[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

[RCR] abstract method in Ruby

Makoto Kuwata

3/11/2006 12:38:00 PM

To define abstract method in Ruby, I use NotImplementedError like the
following:

----------
class Foo
def m1
raise NotImpelemntedError("#{self.class.name}#m1() is not
implemented.")
end
end
----------

I think it is convenient if the Module#abstract_method is defined.

----------
class Module
def abstract_method(*method_names)
method_names.each do |name|
s = <<-END
def #{name}
mesg = "\#{self.class.name}##{name}() is not implemented."
raise NotImplementedError.new(mesg)
end
END
module_eval s
end
end

class Foo
abstract_method :m1, :m2, :m3 # define abstract methods
end

obj = Foo.new
obj.m1 #=> Foo#m1() is not implemented yet. (NotImplementedError)
----------

But this solution doesn't allow us to define a method with arguments.
The following is another solution to define abstract method
which is able to define a method with arguments.

? example.rb
----------
module Abstract # or Module?
def not_implemented # or should_be_implemented?
backtrace = caller()
method_name = (backtrace.shift =~ /`(\w+)'$/) && $1
mesg = "#{self.class.name}##{method_name}() is not implemented."
err = NotImplementedError.new(mesg)
err.set_backtrace(backtrace)
raise err
end
end

class Foo
include Abstract
def m1(arg)
not_implemented
end
end

obj = Foo.new
p obj.m1('abc') #=> example.rb:20: Foo#m1() is not implemented.
(NotImplementedError)
----------

I think this is useful for everyone and I hope it will be included in
Ruby.
Could you give me any advices?

--
regards,
kwatch

53 Answers

Austin Ziegler

3/11/2006 3:01:00 PM

0

On 3/11/06, kwatch <kwa@kuwata-lab.com> wrote:> To define abstract method in Ruby, I use NotImplementedError like the> following:In the last four years of using Ruby, I thought I needed abstractmethods in the first few months. Then I learned what value Modules asmixins gave me.I do not believe that this is a common enough need that it needs to bein the core of Ruby.I encourage you to do what others have done with this sort ofmismatched feature and make a library that implements it and make itavailable for use. Your pure-Ruby implementation looks more thansufficient.More than that, though, I encourage you to rethink why you needabstract methods. Most of the time this is because you're thinking interms of C++ or Java inheritance, when Ruby's mixins are both morepowerful and applicable in most cases where you would define ahierarchy that has abstract methods.-austin--Austin Ziegler * halostatue@gmail.com * Alternate: austin@halostatue.ca

Makoto Kuwata

3/11/2006 10:20:00 PM

0

Thanks Austin,

Austin Ziegler wrote:
>
> In the last four years of using Ruby, I thought I needed abstract
> methods in the first few months. Then I learned what value Modules as
> mixins gave me.
>
> I do not believe that this is a common enough need that it needs to be
> in the core of Ruby.

Well, I think that abstract method is more basic than 'singleton.rb'
or 'delegate.rb' which are bundled in Ruby.


> I encourage you to do what others have done with this sort of
> mismatched feature and make a library that implements it and make it
> available for use. Your pure-Ruby implementation looks more than
> sufficient.

I'll make it library and register it to RubyForge.


> More than that, though, I encourage you to rethink why you need
> abstract methods. Most of the time this is because you're thinking in
> terms of C++ or Java inheritance, when Ruby's mixins are both more
> powerful and applicable in most cases where you would define a
> hierarchy that has abstract methods.

In my opinion, 'mixin' is one thing and 'abstract method' is another.
Mixin doesn't cover abstract method.

The following is an example of visitor pattern.
It shows that mixin doesn't cover abstract method.

----------
module Visitor
def visit_foo(acceptor) # abstract method
mesg = "#{self.class.name}#visit_foo() is not implemented."
raise NotImplementedError.new(mesg)
end

def visit_bar(acceptor) # abstract method
mesg = "#{self.class.name}#visit_foo() is not implemented."
raise NotImplementedError.new(mesg)
end
end

class MyVisitor
include Visitor # mix-in

def visit_foo(acceptor)
puts "visit_foo() called."
end

def visit_bar(acceptor)
puts "visit_bar() called."
end
end

class Foo
def accept(visitor)
visitor.visit_foo(self)
end
end

class Bar
def accept(visitor)
visitor.visit_bar(self)
end
end
----------

Ruby's mix-in is more sophisticated solution than interface of Java
or multiple inheritance of C++, I think.
But mix-in and abstract method are different thing.

--
regards,
kwatch

Logan Capaldo

3/11/2006 10:58:00 PM

0


On Mar 11, 2006, at 5:23 PM, kwatch wrote:

> Thanks Austin,
>
> Austin Ziegler wrote:
>>
>> In the last four years of using Ruby, I thought I needed abstract
>> methods in the first few months. Then I learned what value Modules as
>> mixins gave me.
>>
>> I do not believe that this is a common enough need that it needs
>> to be
>> in the core of Ruby.
>
> Well, I think that abstract method is more basic than 'singleton.rb'
> or 'delegate.rb' which are bundled in Ruby.
>
>
>> I encourage you to do what others have done with this sort of
>> mismatched feature and make a library that implements it and make it
>> available for use. Your pure-Ruby implementation looks more than
>> sufficient.
>
> I'll make it library and register it to RubyForge.
>
>
>> More than that, though, I encourage you to rethink why you need
>> abstract methods. Most of the time this is because you're thinking in
>> terms of C++ or Java inheritance, when Ruby's mixins are both more
>> powerful and applicable in most cases where you would define a
>> hierarchy that has abstract methods.
>
> In my opinion, 'mixin' is one thing and 'abstract method' is another.
> Mixin doesn't cover abstract method.
>
> The following is an example of visitor pattern.
> It shows that mixin doesn't cover abstract method.
>
> ----------
> module Visitor
> def visit_foo(acceptor) # abstract method
> mesg = "#{self.class.name}#visit_foo() is not implemented."
> raise NotImplementedError.new(mesg)
> end
>
> def visit_bar(acceptor) # abstract method
> mesg = "#{self.class.name}#visit_foo() is not implemented."
> raise NotImplementedError.new(mesg)
> end
> end
>
> class MyVisitor
> include Visitor # mix-in
>
> def visit_foo(acceptor)
> puts "visit_foo() called."
> end
>
> def visit_bar(acceptor)
> puts "visit_bar() called."
> end
> end
>
> class Foo
> def accept(visitor)
> visitor.visit_foo(self)
> end
> end
>
> class Bar
> def accept(visitor)
> visitor.visit_bar(self)
> end
> end
> ----------
>
> Ruby's mix-in is more sophisticated solution than interface of Java
> or multiple inheritance of C++, I think.
> But mix-in and abstract method are different thing.
>
> --
> regards,
> kwatch
>
>

I think you're over engineering. Let's consider the Enumerable module
for instance. It has an "abstract" method of sorts, each.

class A
include Enumerable
end

a = A.new
a.map { |x| x + 1 }

Oh look, this code already raises an exception, a NoMethodError. Now
I know that to include Enumerable I have to have an each method.
That's all there is to it. Look at your Visitor example for instance,
in ruby there's not even a need for the Visitor module, all you have
to do is implement visit_foo and visit_bar in MyVisitor. In ruby, no
one cares who your parents were, all they care about is if you know
what you are talking about.

class MyVisitor
def visit_foo(acceptor)
puts "visit_foo() called."
end

def visit_bar(acceptor)
puts "visit_bar() called."
end
end

class Foo
def accept(visitor)
visitor.visit_foo(self)
end
end

class Bar
def accept(visitor)
vistor.visit_bar(self)
end
end

Bam! Same thing as your code, will still raise the same exceptions,
but ONLY if you really need them. Start thinking like a duck man. Ask
yourself what is the purpose of an abstract method. Then ask yourself
if that need is already fufilled in ruby.



Jacob Fugal

3/11/2006 11:53:00 PM

0

On 3/11/06, kwatch <kwa@kuwata-lab.com> wrote:
> I think it is convenient if the Module#abstract_method is defined.

I'm of a similar opinion with others that predeclaring an abstract
method that raises NotImplementedError is of limited use when compared
with the existing NoMethodError duck-typing approach. As such, I don't
think it belongs in the core.

*However*, this is a useful concept which could be used to extend the
capabilities of the language for those who do still want it. I
encourage you to build a library from this idea and publicize it. Just
because it doesn't belong in the core doesn't mean it won't be useful
to some. One place I can see this being used is if the
NotImplementedError gave a more descriptive output, such as "#{self}
requires that the host implement the method '#{method_name}'." E.g.
"Enumerable requires that the host implement the method 'each'."

> ----------
> class Module
> def abstract_method(*method_names)
> method_names.each do |name|
> s = <<-END
> def #{name}
> mesg = "\#{self.class.name}##{name}() is not implemented."
> raise NotImplementedError.new(mesg)
> end
> END
> module_eval s
> end
> end
>
> class Foo
> abstract_method :m1, :m2, :m3 # define abstract methods
> end
>
> obj = Foo.new
> obj.m1 #=> Foo#m1() is not implemented yet. (NotImplementedError)
> ----------
>
> But this solution doesn't allow us to define a method with arguments.

One thing that you can do to make this approach (which seems cleaner
and simpler than the backtrace manipulation approach you later
proposed) more flexible by removing the arity restriction on the
method using the splat operator:

$ cat abstract.rb
class Module
def abstract_method(*method_names)
mesg_template = "#{self} requires that the host implement the
method '%s'."
method_names.each do |name|
mesg = mesg_template % [name]
module_eval <<-END
def #{name}(*args)
raise NotImplementedError.new("#{mesg}")
end
END
end
end
end

module MyModule
def foo
bar("test")
end

abstract_method :bar
end

class MyClass
include MyModule
end

a = MyClass.new
b = MyClass.new

class << a
def bar( s )
puts s
end
end

a.foo
b.foo

$ ruby abstract.rb
test
(eval):2:in `bar': MyModule requires that the host implement the
method 'bar'. (NotImplementedError)
from abstract.rb:17:in `foo'
from abstract.rb:37

--
Jacob Fugal


Makoto Kuwata

3/12/2006 7:37:00 AM

0

Logan,

> Oh look, this code already raises an exception, a NoMethodError. Now
> I know that to include Enumerable I have to have an each method.
> That's all there is to it.

I think it is very important that the code itself is descriptive.
The following code doesn't describe that method each() is abstract.

module Enumerable
def map
arr = []
each { |elem| arr << yield(elem) }
arr
end
end

The following code itself describes that method each() is abstract.
It's more descriptive.

module Enumerable
abstract_method :each
def map
arr = []
each { |elem| arr << yield(elem) }
arr
end
end

Please take care of reading code, as well as writing code.
You may insist that documentation is sufficient to describe that,
but documentation is assistant and code should be prime.


> Oh look, this code already raises an exception, a NoMethodError.

NoMethodError is not proper to abstract method, I think.


> Look at your Visitor example for instance,
> in ruby there's not even a need for the Visitor module, all you have
> to do is implement visit_foo and visit_bar in MyVisitor. In ruby, no
> one cares who your parents were, all they care about is if you know
> what you are talking about.

Assume that you need to define many visitor classes.

module Visitor
abstract_method :visit_foo, :visit_bar
end

class Hoge
include Visitor
def visit_foo; ... ; end
def visit_bar; ... ; end
end

class Fuga
include Visitor
def visit_foo; ... ; end
def visit_bar; ... ; end
end

class Geji
include Visitor
def visit_foo; ... ; end
def visit_bar; ... ; end
end

The above code itself describes that "class Hoge, Fuga, and Geji
are visotr classes" very clearly.
'Visitor' module may not be necessary when a number of visitor class
is only 1.
But there should be 'Visitor' module in the case that many visitor
classes are needed. It's more descriptive.


> Start thinking like a duck man.

You mean 'duck typing'?
Duck typing is one thing and abstract method is another.


> Ask yourself what is the purpose of an abstract method.
> Then ask yourself if that need is already fufilled in ruby.

Abstract method is useful to realize 'descriptive code'.
It increases code maintanancability.


--
regards,
kwatch


Logan Capaldo wrote:

> On Mar 11, 2006, at 5:23 PM, kwatch wrote:
>
> > Thanks Austin,
> >
> > Austin Ziegler wrote:
> >>
> >> In the last four years of using Ruby, I thought I needed abstract
> >> methods in the first few months. Then I learned what value Modules as
> >> mixins gave me.
> >>
> >> I do not believe that this is a common enough need that it needs
> >> to be
> >> in the core of Ruby.
> >
> > Well, I think that abstract method is more basic than 'singleton.rb'
> > or 'delegate.rb' which are bundled in Ruby.
> >
> >
> >> I encourage you to do what others have done with this sort of
> >> mismatched feature and make a library that implements it and make it
> >> available for use. Your pure-Ruby implementation looks more than
> >> sufficient.
> >
> > I'll make it library and register it to RubyForge.
> >
> >
> >> More than that, though, I encourage you to rethink why you need
> >> abstract methods. Most of the time this is because you're thinking in
> >> terms of C++ or Java inheritance, when Ruby's mixins are both more
> >> powerful and applicable in most cases where you would define a
> >> hierarchy that has abstract methods.
> >
> > In my opinion, 'mixin' is one thing and 'abstract method' is another.
> > Mixin doesn't cover abstract method.
> >
> > The following is an example of visitor pattern.
> > It shows that mixin doesn't cover abstract method.
> >
> > ----------
> > module Visitor
> > def visit_foo(acceptor) # abstract method
> > mesg = "#{self.class.name}#visit_foo() is not implemented."
> > raise NotImplementedError.new(mesg)
> > end
> >
> > def visit_bar(acceptor) # abstract method
> > mesg = "#{self.class.name}#visit_foo() is not implemented."
> > raise NotImplementedError.new(mesg)
> > end
> > end
> >
> > class MyVisitor
> > include Visitor # mix-in
> >
> > def visit_foo(acceptor)
> > puts "visit_foo() called."
> > end
> >
> > def visit_bar(acceptor)
> > puts "visit_bar() called."
> > end
> > end
> >
> > class Foo
> > def accept(visitor)
> > visitor.visit_foo(self)
> > end
> > end
> >
> > class Bar
> > def accept(visitor)
> > visitor.visit_bar(self)
> > end
> > end
> > ----------
> >
> > Ruby's mix-in is more sophisticated solution than interface of Java
> > or multiple inheritance of C++, I think.
> > But mix-in and abstract method are different thing.
> >
> > --
> > regards,
> > kwatch
> >
> >
>
> I think you're over engineering. Let's consider the Enumerable module
> for instance. It has an "abstract" method of sorts, each.
>
> class A
> include Enumerable
> end
>
> a = A.new
> a.map { |x| x + 1 }
>
> Oh look, this code already raises an exception, a NoMethodError. Now
> I know that to include Enumerable I have to have an each method.
> That's all there is to it. Look at your Visitor example for instance,
> in ruby there's not even a need for the Visitor module, all you have
> to do is implement visit_foo and visit_bar in MyVisitor. In ruby, no
> one cares who your parents were, all they care about is if you know
> what you are talking about.
>
> class MyVisitor
> def visit_foo(acceptor)
> puts "visit_foo() called."
> end
>
> def visit_bar(acceptor)
> puts "visit_bar() called."
> end
> end
>
> class Foo
> def accept(visitor)
> visitor.visit_foo(self)
> end
> end
>
> class Bar
> def accept(visitor)
> vistor.visit_bar(self)
> end
> end
>
> Bam! Same thing as your code, will still raise the same exceptions,
> but ONLY if you really need them. Start thinking like a duck man. Ask
> yourself what is the purpose of an abstract method. Then ask yourself
> if that need is already fufilled in ruby.

Makoto Kuwata

3/12/2006 8:13:00 AM

0

Jacob Fugal wrote:
>
> I'm of a similar opinion with others that predeclaring an abstract
> method that raises NotImplementedError is of limited use when compared
> with the existing NoMethodError duck-typing approach. As such, I don't
> think it belongs in the core.

Hmm...
IMO, abstract method is more useful than 'singleton.rb' or
'delegate.rb'.
It's just my opinion.


> *However*, this is a useful concept which could be used to extend the
> capabilities of the language for those who do still want it. I
> encourage you to build a library from this idea and publicize it. Just
> because it doesn't belong in the core doesn't mean it won't be useful
> to some.

Yes, I'm going to release 'abstract.rb'.


> One place I can see this being used is if the
> NotImplementedError gave a more descriptive output, such as "#{self}
> requires that the host implement the method '#{method_name}'." E.g.
> "Enumerable requires that the host implement the method 'each'."
....(snip)...
> One thing that you can do to make this approach (which seems cleaner
> and simpler than the backtrace manipulation approach you later
> proposed) more flexible by removing the arity restriction on the
> method using the splat operator:

Thaks for your good advice.
I changed Module#abstract_method() like the following:

----------
class Module
def abstract_method args_str, *method_names
method_names.each do |name|
mesg = "class %s should implement abstract method
`#{self.name}##{name}()'."
module_eval <<-END
def #{name}(#{args_str})
err = NotImplementedError.new(mesg % self.class.name)
err.set_backtrace caller()
raise err
end
END
end
end
end
----------

Manipulating backtrace of exception is need in order to show
linenumber in which an abstract method is invoked.

example:

----------
require 'abstract'
class Foo
abstract_method '*args', :m1, :m2 # removing the arity
restriction
end
class Bar < Foo
def m1; puts "Foo#m1() called."; end
end
obj = Bar.new
obj.m1 #=> "Foo#m1() called."
obj.m2 #=> ex.rb:10: class Bar should implement abstract method
`Foo#m2()'. (NotImplementedError)
----------


--
regards,
kwatch


Jacob Fugal wrote:

> On 3/11/06, kwatch <kwa@kuwata-lab.com> wrote:
> > I think it is convenient if the Module#abstract_method is defined.
>
> I'm of a similar opinion with others that predeclaring an abstract
> method that raises NotImplementedError is of limited use when compared
> with the existing NoMethodError duck-typing approach. As such, I don't
> think it belongs in the core.
>
> *However*, this is a useful concept which could be used to extend the
> capabilities of the language for those who do still want it. I
> encourage you to build a library from this idea and publicize it. Just
> because it doesn't belong in the core doesn't mean it won't be useful
> to some. One place I can see this being used is if the
> NotImplementedError gave a more descriptive output, such as "#{self}
> requires that the host implement the method '#{method_name}'." E.g.
> "Enumerable requires that the host implement the method 'each'."
>
> > ----------
> > class Module
> > def abstract_method(*method_names)
> > method_names.each do |name|
> > s = <<-END
> > def #{name}
> > mesg = "\#{self.class.name}##{name}() is not implemented."
> > raise NotImplementedError.new(mesg)
> > end
> > END
> > module_eval s
> > end
> > end
> >
> > class Foo
> > abstract_method :m1, :m2, :m3 # define abstract methods
> > end
> >
> > obj = Foo.new
> > obj.m1 #=> Foo#m1() is not implemented yet. (NotImplementedError)
> > ----------
> >
> > But this solution doesn't allow us to define a method with arguments.
>
> One thing that you can do to make this approach (which seems cleaner
> and simpler than the backtrace manipulation approach you later
> proposed) more flexible by removing the arity restriction on the
> method using the splat operator:
>
> $ cat abstract.rb
> class Module
> def abstract_method(*method_names)
> mesg_template = "#{self} requires that the host implement the
> method '%s'."
> method_names.each do |name|
> mesg = mesg_template % [name]
> module_eval <<-END
> def #{name}(*args)
> raise NotImplementedError.new("#{mesg}")
> end
> END
> end
> end
> end
>
> module MyModule
> def foo
> bar("test")
> end
>
> abstract_method :bar
> end
>
> class MyClass
> include MyModule
> end
>
> a = MyClass.new
> b = MyClass.new
>
> class << a
> def bar( s )
> puts s
> end
> end
>
> a.foo
> b.foo
>
> $ ruby abstract.rb
> test
> (eval):2:in `bar': MyModule requires that the host implement the
> method 'bar'. (NotImplementedError)
> from abstract.rb:17:in `foo'
> from abstract.rb:37
>
> --
> Jacob Fugal

Meinrad Recheis

3/12/2006 8:26:00 AM

0

On 3/12/06, kwatch <kwa@kuwata-lab.com> wrote:
[...]

> Duck typing is one thing and abstract method is another.
>
>
hi kwatch,
if you want serious discussion then it would be great if you were able to
tell us why you think so.
a statement (alone) is nothing worth if it is not supported by reasonable
arguments.

-- henon

Logan Capaldo

3/12/2006 3:26:00 PM

0


On Mar 12, 2006, at 2:38 AM, kwatch wrote:

> I think it is very important that the code itself is descriptive.
> The following code doesn't describe that method each() is abstract.

I think then we have a difference of opinion of the meaning and usage
of abstract methods.
I am of the opinion that they exist to enforce stronger typing,
especially at compile time. It's a solution to the problem of having
a class we're the implementation of a given method is given to a
child class but all methods available to a class must be known at
compile time. It's especially helpful when the abstract method must
return something, and there is no sane default.

class A {
int someAbstractMethod( ) {
// If I don't have abstract methods, what should I return?
// whatever I return, it won't be correct and it won't
force child classes
// to implement me
}
}


OTOH in ruby since it's dynamically typed, the compiler won't
complain about undefined methods until they actually get called (if
they are still undefined)

eg
class A {
someOtherMethod( ) {
x = someAbstractMethod( ); // forces child classes to
implement it simply by calling it
}
}

Now if you want to have an argument about static vs. dynamic typing
that's one thing. You say that it's important that code be
descriptive. You also say that documentation is insufficient. I
disagree, and say no code is possibly descriptive enough. Whether
attempting to call a method
that relies on an "abstract" method raises a NoMethodError or a
NotImplementedError the result is the same. The programmer must go
read the documentation (or possibly the calling code) to figure out
what was expected of him.

Basically, I feel abstract methods are a primarily feature of static
typing and help ensure the correctness of your code. But they are a
typing feature and the error message you get from them isn't any more
descriptive than "function max expected int, got string"

Tangentially related to this, I find your Visitor example a little
weak, since your Visitor module provides no methods of its own.
Modules are not Java interfaces, and the only reason to write
"include Visitor" in your code is to say
# this class implements the methods required to visit other objects
I think you've turned the idea of descriptive code into a degenerate
case of ALL this code does is describe. It has no functional purpose.
It's like using no-ops to spell out documentation in morse-code :)
(admittedly, that analogy is a bit ridiculous).

Feel free to ignore the previous paragraph by saying something along
the lines of "Well of course a real visitor module would have
additional methods, it was just an example." :)

Erik Veenstra

3/12/2006 8:20:00 PM

0

> To define abstract method in Ruby, I use NotImplementedError
> like the following:

You can't call them *abstract* methods if you implement them
like this.

In Java, the presence of methods is checked at compiletime, if
they are defined "abstract". Your solution only checks the
presence of these methods at runtime, which is already checked
by Ruby itself.

So, what functionality or checks are you really adding?

gegroet,
Erik V. - http://www.erikve...

Austin Ziegler

3/12/2006 8:49:00 PM

0

On 3/12/06, kwatch <kwa@kuwata-lab.com> wrote:> Logan,>> Oh look, this code already raises an exception, a NoMethodError. Now>> I know that to include Enumerable I have to have an each method.>> That's all there is to it.> I think it is very important that the code itself is descriptive. The> following code doesn't describe that method each() is abstract.> module Enumerable> def map> arr = []> each { |elem| arr << yield(elem) }> arr> end> endActually, the method #each is not abstract in Enumerable. It's aprerequisite. There's a difference. In the C++ and Java world, it's*necessary* to define a prerequisite method as an abstract method,because without a method definition, the compiler goes stupid and can'tfind anything and won't then compile your code at all. Ruby sees thecall to #each with a block and says "okay, I'll trust that you'vesatisified this until I hit it at run time."> The following code itself describes that method each() is abstract.> It's more descriptive.> module Enumerable> abstract_method :each> def map> arr = []> each { |elem| arr << yield(elem) }> arr> end> end> Please take care of reading code, as well as writing code. You may> insist that documentation is sufficient to describe that, but> documentation is assistant and code should be prime.What you've got is no better than: # Every method provided in Enumerable requires that the including # class defines an #each method that iterates one item at a time. module Enumerable def map arr = [] each { |elem| arr << yield(elem) } arr end endExcept that it actually adds a little code for what is essentially adocumentation annotation. As I said, it adds little to no value to Rubyand IMO doesn't belong in the core.>> Oh look, this code already raises an exception, a NoMethodError.> NoMethodError is not proper to abstract method, I think.I think that it is. It says that there's no method for what's beinglooked for. Having "abstract_method :each" doesn't add value to that.>> Look at your Visitor example for instance,>> in ruby there's not even a need for the Visitor module, all you have>> to do is implement visit_foo and visit_bar in MyVisitor. In ruby, no>> one cares who your parents were, all they care about is if you know>> what you are talking about.>> Assume that you need to define many visitor classes.>> module Visitor> abstract_method :visit_foo, :visit_bar> end>> class Hoge> include Visitor> def visit_foo; ... ; end> def visit_bar; ... ; end> end>> class Fuga> include Visitor> def visit_foo; ... ; end> def visit_bar; ... ; end> end>> class Geji> include Visitor> def visit_foo; ... ; end> def visit_bar; ... ; end> end>> The above code itself describes that "class Hoge, Fuga, and Geji> are visotr classes" very clearly.> 'Visitor' module may not be necessary when a number of visitor class> is only 1.> But there should be 'Visitor' module in the case that many visitor> classes are needed. It's more descriptive.Disagree. In Ruby, inclusion of a Module means something. Specifically,it means that you're mixing in functionality ... not that you're mixingin warnings or merely documenting things. # Items of class Hoge can be visited by classes that know how to # #visit_foo or #visit_bar. class Hoge def visit_foo; ... ; end def visit_bar; ... ; end end # Items of class Fuga can be visited by classes that know how to # #visit_foo or #visit_bar. class Fuga def visit_foo; ... ; end def visit_bar; ... ; end end # Items of class Geji can only be visited by classes that know how # to #visit_foo. class Geji def visit_foo; ... ; end end>> Start thinking like a duck man.> You mean 'duck typing'? Duck typing is one thing and abstract method> is another.Not really. As I noted earlier, abstract methods are necessary instatically typed and linked languages because they're aggressive inresolving "facts", whereas Ruby is lazy and doesn't try to resolvethings until they're needed.>> Ask yourself what is the purpose of an abstract method.>> Then ask yourself if that need is already fufilled in ruby.> Abstract method is useful to realize 'descriptive code'.> It increases code maintanancability.Disagree. IME, it does the opposite and reduces the descriptiveness andusefulness of the code. Stop thinking in C++ -- in Ruby, abstractmethods simply aren't necessary.Trust me. You won't find them in Rails, PDF::Writer, or any of a varietyof other large and popular packages.-austin--Austin Ziegler * halostatue@gmail.com * Alternate: austin@halostatue.ca