Makoto Kuwata
3/12/2006 7:37:00 AM
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.