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.