On Oct 6, 2007, at 7:48 PM, Jason P. wrote:
(The one sticking point I would occasionally hit was delegation, as
[offlist]I’m enjoying this thread. Would you please consider elaborating on
this notion in the thread itself?
Sure, I’ll try.
For the record though, the issues I’m about to discuss don’t seem to
relate to Sylvain’s complaints about a lack of MI. For that reason,
I’ve renamed this subthread.
Delegation is a form of composition, like inheritance. The design
patterns movement has pushed that delegation is is more flexible to
inheritance and should be preferred when we are designing objects.
It comes in many, many forms but one example might be that we want a
strict Queue object. We want to allow enqueueing and dequeuing items
and peeking at the top item, but we don’t want users accessing items
in the middle of the Queue. One way to create this is to delegate
the needed operations to an Array:
require “forwardable”
class Queue
def initialize
@queue = Array.new
end
extend Forwardable
def_delegators :@queue, :shift, :<<
alias_method :enqueue, :<<
alias_method :dequeue, :shift
def peek
@queue.first # don’t delegate because it allows: first(n)
end
end
if FILE == $PROGRAM_NAME
q = Queue.new
%w[one two three].each { |num| q.enqueue num }
4.times { p q.dequeue }
end
END
Duck typing is a concept that says we should view the type of an
object by what it can do, more than what it is. The deeper you go
with this line of thought you generally come to realize than type
checking can often be avoided and leads to more powerful code when it
is. For example, an add_event() method could work with an Array, our
new Queue, or something else entirely:
$ irb -r queue
def add_event(event_list)
event_list << :event
end
=> niladd_event(Array.new)
=> [:event]q = Queue.new
=> #Queue:0x14f6ce8add_event(q)
=> [:event]q.peek
=> :event
This are simplified explanations, but hopefully the begin to
illustrate the differences.
James Edward G. II