On Tue, 14 Mar 2006, ilan berci wrote:
A good portion of the GoF patterns rely on abstract methods (visitor,
abstract factory, template method, etc… ) which IMO only shine in
statically typed languages. It would be a shame to port all patterns (and
their required prerequisite: abstract methods) simply because they are
recognized in the static world and therefore would make a good fit in Ruby.
The additional code needed for the ruby “abstract method” approach doesn’t
make the code any more readable. The extra LoC actually slows down the
maintenance developer as she has to wade through more.
i disagree strongly here. check out these two snippets that i am
working on
as we speak:
def will_process_holding *a, &b
raise NotImplementedError
end
def process_holding *a, &b
raise NotImplementedError
end
def will_process_incoming(*a, &b)
raise NotImplementedError
end
def process_incoming(*a, &b)
raise NotImplementedError
end
vs
abstract_method "will_process_holding"
abstract_method "process_holding"
abstract_method "will_process_incoming"
abstract_method "process_incoming"
it’s for precisely these kinds of simple repetetive defs that we have
‘attr’,
‘attr_accessor’, ‘attr_writer’, and ‘attr_reader’. think about how
simple all
these methods are to write - but people love the shorthand and the fact
that
rdoc can grok something meaningful from the metaprogramming is quite
beneficial.
sure - i could just go full on duck type - but good luck reading the
2000 line
satellite image processing library that requires these four methods (and
about
20 others) and trying to figure out which ones you need to implement. i
nice
compact listing like this surely helps out with that task doesn’t it?
here’s another example from the standard lib
tsort.rb
...
#
# Should be implemented by a extended class.
#
# #tsort_each_node is used to iterate for all nodes over a graph.
#
def tsort_each_node # :yields: node
raise NotImplementedError.new
end
#
# Should be implemented by a extended class.
#
# #tsort_each_child is used to iterate for child nodes of _node_.
#
def tsort_each_child(node) # :yields: child
raise NotImplementedError.new
end
...
now, all this starts out at about line 230. this is a little deep is it
not?
i think it’d be great of rdoc understood and abstract_method hook just
like it
now supports the ‘attr_XXX’ hooks but, even without that, i’ll take any
hint i
can get in code like this.
ask yourself this: why did the author not just rely on duck-typing? why
put
these methods into the code at all?
In both solutions, an exception is thrown at runtime. The abstract method
approach will not allow the developer to catch it any earlier than the duck
typed default.
unless, using one approach it takes an hour to figure out which methods
to
impliment and the other way it does not. consider an abstract method
module Interface
def extra_debugging_info e
…
end
end
used like
module Interface
def foobar
begin
…
…
rescue ExceptionThatOccursOncePerMonth => e
logger.warn{ extra_debugging_info e}
end
end
end
how anoying! you really should have written that method because your
code now
fails once per month. having an ‘abstract_method’ hook makes it so,
even if
the developer didn’t comment their code, the code itself clearly showed
the
list of methods which should be implimented.
trust me - i realize this is really a small gain over pure duck typing -
but
for the kinds of systems i’m writing, with 10,000 lines of ruby code,
it’s
really quite helpful to have this sort of note to myself jump out in the
code. that’s why i’ve already written this:
class Subscription
…
def self::abstract_method m
module_eval <<-definition
def #{ m }(*a, &b)
raise NotImplementedError
end
definition
end
…
The exception proposed although slightly more readable will not in
practice add any value as Ruby developers are used to seeing the
exception and can narrow in on it expediently.
agreed. the point is to not get the exception in the first place
becausee the
code was easier to understand how to hook into.
We should simply rejoice in the power of the mixin and realize that the
abstract specifier was devised prior to (and probably due to the absence
of) this incredibly powerfull construct.
Lastly, the code becomes somewhat heavier which violates 2 key
principles of Ruby, one being the enjoyable to code principle, and the
other, least surprise principle.
i really don’t see why people would object to this idea. is it because
people
are only writing 100 line programs in ruby that might require one
abstract
method? i just don’t understand how someone could think that diving
into a
complex inheritence hierarchy of 30 classes/modules requiring 20 or so
abstract
methods would NOT be made easier to grok if one could grep for
/abstract_method/ in their editor to get a jump on things…
my 2cts.
kind regards.
-a