How to simulate self-style delegation

I have classes A and B.

class A
  def x
    "A::x "
  end
  def xy
    self.x + "A::y"
  end
end

class B
  def initialize a
    @a = a
  end
  def x
    "B::x "
  end
  def method_missing ???
    ?? SELF-style delegate to @a
  end
end

I want true SELF-style delegation from objects of class B to A. i.e. self
calls on an A are in the context of the delegating B (if any).

a = A.new
a.xy #=> "A::x A::y"

b = B.new a

b.xy #=> "B::x A::y"
    # calls b.method missing
    # calls a.xy
    # calls b.x #=> "B::x"
    # calls a.y #=> "A::y"
    # return "B::x A::y"

How can I do this?

Thanks!

"itsme213" <itsme213@hotmail.com> schrieb im Newsbeitrag
news:y463e.17923$1H3.10469@tornado.texas.rr.com...

I have classes A and B.

class A
  def x
    "A::x "
  end
  def xy
    self.x + "A::y"
  end
end

class B
  def initialize a
    @a = a
  end
  def x
    "B::x "
  end
  def method_missing ???
    ?? SELF-style delegate to @a
  end
end

I want true SELF-style delegation from objects of class B to A. i.e.

self

calls on an A are in the context of the delegating B (if any).

a = A.new
a.xy #=> "A::x A::y"

b = B.new a

b.xy #=> "B::x A::y"
    # calls b.method missing
    # calls a.xy
    # calls b.x #=> "B::x"
    # calls a.y #=> "A::y"
    # return "B::x A::y"

How can I do this?

From all that I know you can't because you cannot do any of these:

- bind an instance method of A to B (unless B is a superclass of A)

- convert a method to a proc that is usable with instance_eval.

The question is: does it make sense to do that?

Kind regards

    robert

Below's my test code.

class A
  def x
    "A::x "
  end
  def xy
    self.x + "A::y"
  end
end

class B
  def initialize a
    @a = a
  end
  def x
    "B::x "
  end
  # def respond_to?(*x) true end
  def method_missing(sym, *args, &bl)
    ppp = @a.method(sym).to_proc
    # p ppp.arity
    class<<self; self; end.class_eval { define_method(sym){ instance_eval
&ppp } }
    # class<<self; self; end.class_eval { define_method(sym){ p self } }
    # p respond_to?( sym )
    send(sym,args)
    # self.instance_eval &ppp
    # instance_eval { ppp.call(*args) }
  end
end

b=B.new A.new
# set_trace_func lambda {|*a| p a}
p b.xy

What I can imagine:

1)

* create a joint proxy object for a and b (something along the lines of
the cuckoo of
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/128368,
just the method_missing of the proxy should look at both a and b)

* copy all instance_variables of b to the proxy

* define a method_missing for b which resends the message :xy to the
proxy object (somehow you should exclude circular method_missing calls
between b and the proxy)

This work by-and-large as long as you don't overwrite instance variables
in b. If you have an instance variable which gets overwritten
frequently, make a custom setter for it which updates the proxy as well.

or

2)

* Make A a module which extends itself

* define A.new similarly to this:

  def new
    a = Module.new
    a.send :include, self
    a.extend a
  end

  Now A quacks like a class.

* in B.initialize, extend the instance with a.

However, it pulls in the whole A "instance", and delegation is not
limited to #xy.

Csaba

···

On 2005-04-01, itsme213 <itsme213@hotmail.com> wrote:

I have classes A and B.

class A
  def x
    "A::x "
  end
  def xy
    self.x + "A::y"
  end
end

class B
  def initialize a
    @a = a
  end
  def x
    "B::x "
  end
  def method_missing ???
    ?? SELF-style delegate to @a
  end
end

I want true SELF-style delegation from objects of class B to A. i.e. self
calls on an A are in the context of the delegating B (if any).

a = A.new
a.xy #=> "A::x A::y"

b = B.new a

b.xy #=> "B::x A::y"
    # calls b.method missing
    # calls a.xy
    # calls b.x #=> "B::x"
    # calls a.y #=> "A::y"
    # return "B::x A::y"

How can I do this?

How do you mean "make sense"? Does my desired behavior make sense (it does
to me)? Or does it make sense for Ruby to permit one of the 2 approaches you
suggest (#2 does, not sure I understood #1)?

Thanks.

btw, my guess at what the instance_eval version might look like:

class B
def initialize delegatee
   @a = delegatee
end
def method_missing sym, *args, &block
  m = @a.method sym
  self.instance_eval m, *args, &block
end
end

···

"Robert Klemme" <bob.news@gmx.net> wrote

From all that I know you can't because you cannot do any of these:

- bind an instance method of A to B (unless B is a superclass of A)

- convert a method to a proc that is usable with instance_eval.

The question is: does it make sense to do that?

"itsme213" <itsme213@hotmail.com> schrieb im Newsbeitrag news:NUe3e.22640$1H3.7060@tornado.texas.rr.com...

From all that I know you can't because you cannot do any of these:

- bind an instance method of A to B (unless B is a superclass of A)

- convert a method to a proc that is usable with instance_eval.

The question is: does it make sense to do that?

How do you mean "make sense"?

"Does it make sense to steal a method from a class and make it execute on another classes instance?" I mean, you cannot generally expect that all methods the "stolen" method requires are present in the other class. (I know that's why you use the fallback but then again, what does one gain? You can, for exaple, inject methods temporarily into the other instance.)

Does my desired behavior make sense (it does to me)?

Apparently. :slight_smile: But in what use case do you need this? Although Ruby is amazingly dynamic not all features we can think of actually make sense.

Or does it make sense for Ruby to permit one of the 2 approaches you
suggest (#2 does, not sure I understood #1)?

Thanks.

btw, my guess at what the instance_eval version might look like:

class B
def initialize delegatee
  @a = delegatee
end
def method_missing sym, *args, &block
m = @a.method sym
self.instance_eval m, *args, &block
end

Won't work as far as my experiements seem to indicate.

Here's another idea: how about copying instance state around?

Kind regards

    robert

···

"Robert Klemme" <bob.news@gmx.net> wrote

"Does it make sense to steal a method from a class and make it execute on
another classes instance?" I mean, you cannot generally expect that all
methods the "stolen" method requires are present in the other class. (I
know that's why you use the fallback but then again, what does one gain?
You can, for exaple, inject methods temporarily into the other instance.)

I think this is how delegation is used in object-based languages like SELF.
It's a way for B to dynamically inherit at the object-level from A, both
behavior and state. Copying behavior would need copying state, which may not
be practical (how deep to copy, what about state change, etc.).

> Does my desired behavior make sense (it does to me)?

Apparently. :slight_smile: But in what use case do you need this? Although Ruby is
amazingly dynamic not all features we can think of actually make sense.

I want to wrap one object (B) around another (A). B should get all of A's
behavior and state, customized by any methods on B. The behavior and state
of the A should be unchanged as it's methods may be invoked independently.

My specific use case needs a wide variety of ways of merging object graphs
(a bit like Joel's SuperHash, but deep + broad graphs and full control over
inheritance and merge rules). Given graphs g1,g2, I want to create their
merge g3:
  g3.delegate_to(g1, g2)
Then any property on g3 is either defined by a method on g3, or determined
by the logic of method_missing on g3. Which would delegate to g1, g2 and
merge their results ... with the CAVEAT that g1,g2 recursive calls for other
properties would always try g3 first.

Don't know if I explained it well. I'm sure I can find other approaches too,
like passing an explicit and optional _delegator_ parameter to all calls. I
was curious how well I could emulate SELF-like delegation as it would fit
very well.

> btw, my guess at what the instance_eval version might look like:
>
> class B
> def initialize delegatee
> @a = delegatee
> end
> def method_missing sym, *args, &block
> m = @a.method sym
> self.instance_eval m, *args, &block
> end
> end

Won't work as far as my experiements seem to indicate.

Correct. I meant "my guess at what the instance_eval version might look like
IF instance_eval worked for rebinding self for methods".

Here's another idea: how about copying instance state around?

I would have to be very careful with that, due to state changes.

Thanks for the ideas!

···

"Robert Klemme" <bob.news@gmx.net> wrote

Con fecha 2/4/2005, "itsme213" <itsme213@hotmail.com> escribió:

"Does it make sense to steal a method from a class and make it execute on
another classes instance?" I mean, you cannot generally expect that all
methods the "stolen" method requires are present in the other class. (I
know that's why you use the fallback but then again, what does one gain?
You can, for exaple, inject methods temporarily into the other instance.)

I think this is how delegation is used in object-based languages like SELF.
It's a way for B to dynamically inherit at the object-level from A, both
behavior and state. Copying behavior would need copying state, which may not
be practical (how deep to copy, what about state change, etc.).

> Does my desired behavior make sense (it does to me)?

Apparently. :slight_smile: But in what use case do you need this? Although Ruby is
amazingly dynamic not all features we can think of actually make sense.

I want to wrap one object (B) around another (A). B should get all of A's
behavior and state, customized by any methods on B. The behavior and state
of the A should be unchanged as it's methods may be invoked independently.

My specific use case needs a wide variety of ways of merging object graphs
(a bit like Joel's SuperHash, but deep + broad graphs and full control over
inheritance and merge rules). Given graphs g1,g2, I want to create their
merge g3:
g3.delegate_to(g1, g2)
Then any property on g3 is either defined by a method on g3, or determined
by the logic of method_missing on g3. Which would delegate to g1, g2 and
merge their results ... with the CAVEAT that g1,g2 recursive calls for other
properties would always try g3 first.

Don't know if I explained it well. I'm sure I can find other approaches too,
like passing an explicit and optional _delegator_ parameter to all calls. I
was curious how well I could emulate SELF-like delegation as it would fit
very well.

> btw, my guess at what the instance_eval version might look like:
>
> class B
> def initialize delegatee
> @a = delegatee
> end
> def method_missing sym, *args, &block
> m = @a.method sym
> self.instance_eval m, *args, &block
> end
> end

Won't work as far as my experiements seem to indicate.

Correct. I meant "my guess at what the instance_eval version might look like
IF instance_eval worked for rebinding self for methods".

Here's another idea: how about copying instance state around?

I would have to be very careful with that, due to state changes.

I'm not familiar with Self so I'm somewhat at loss as to
what you're gaining with this approach.

Perhaps I'm missing a crucial point here. Should a B 'be' an A
in the normal is_a sense? Should B have access to A's state?
Something more than what SimpleDelegator offers?

method_missing provides a good way if B doesn't need to access
A's state. If such access is desired, for example to implement
a method on B that uses A's state, B can still access A's
instance variables etc.

Thanks for the ideas!

E

···

"Robert Klemme" <bob.news@gmx.net> wrote

itsme213 wrote:

"Does it make sense to steal a method from a class and make it execute on
another classes instance?" I mean, you cannot generally expect that all
methods the "stolen" method requires are present in the other class. (I
know that's why you use the fallback but then again, what does one gain?
You can, for exaple, inject methods temporarily into the other instance.)

I think this is how delegation is used in object-based languages like SELF.
It's a way for B to dynamically inherit at the object-level from A, both
behavior and state. Copying behavior would need copying state, which may not
be practical (how deep to copy, what about state change, etc.).

I'm not 100% sure about self, but some languages that are inspired from self seem to have similar behavior in this department, wherein you aren't actually copying anything; its all done via a prototype lookup chain. Which means, for example, that slot "foo" is not found in object "B", but it exists in object "A" which "B" was cloned from, "B foo" would be a valid message send because it would find the method as part of the lookup chain, "foo" is not copied from "A" to "B" (though you could if you really wanted too, but why bother? this is something that's done for free in a similar manner). (Just to clarify.)

Don't know if I explained it well. I'm sure I can find other approaches too,
like passing an explicit and optional _delegator_ parameter to all calls. I
was curious how well I could emulate SELF-like delegation as it would fit
very well.

In Ruby? Not very easily in any way I can think of without doing some butchering, and dirty hacks (this isn't to say doing what you want isn't possible, I'm just not entirely sure, so I'll refrain from commenting further).

···

"Robert Klemme" <bob.news@gmx.net> wrote

--
Jeremy Tregunna

"Saynatkari" <ruby-ml@magical-cat.org> wrote in message

Perhaps I'm missing a crucial point here. Should a B 'be' an A
in the normal is_a sense? Should B have access to A's state?
Something more than what SimpleDelegator offers?

SELF-style delegation is for "inheriting" at the _object_ level. It lets me
dynamically change the object that b1 delegates to.
    b1 = B.new
    b1.delegate_to(a1)
    ...stuff
    b1.delegate_to(a2)

So
    class B < A; end
does not help.

SimpleDelegator simply forwards missing methods, it does not provide the
binding of self that I am looking for. Here is another example with desired
behavior at the end.

class Role
  def initialize(type)
    @type = type
  end
  def name
    "unbound"
  end
  def describe
    "I am #{self.name}, a #{@type}"
  end
end

PM = Role.new("Project Manager")
GA = Role.new("Graphic Artist")

class Person
  attr_accessor :name
  def delegate_to
    ?? method_missing and self_binding magic here
  end
end

JOE = Person.new
JOE.name = "Joe"

JOE.delegate_to(PM)
JOE.describe #=> "I am Joe, a Project Manager"

JOE.delegate_to(GA)
JOE.describe #=> "I am Joe, a Graphic Artist"

Hope that is more clear. Maybe this is not possible in Ruby ... but I just
got a pointer to _evil_ ruby, perhaps that might have something?

itsme213 schrieb:

My specific use case needs a wide variety of ways of merging object graphs
(a bit like Joel's SuperHash, but deep + broad graphs and full control over
inheritance and merge rules). Given graphs g1,g2, I want to create their
merge g3:
  g3.delegate_to(g1, g2)

I'm also interested in this subject. What I'm trying to do is to join object graphs that don't have to know about each other. I call the medium between the object graphs "seams" (it rhymes with "object teams", see [1] and [2]). As yet, I have coded the basics only, some AOP like functions. With object seams, the method "delegate_to" in your role/person example could be coded as

   require "seam"

   class Person
     def delegate_to(role)
       @seam.clear if @seam
       @seam = Seam.new do |s|
         s.instead_of(self, :describe) do role.describe end
         s.instead_of(role, :name) do self.name end
       end
     end
   end

Send me a mail, if you're interested, and I'll add the preliminary code to my rubyforge project (which is still empty).

Regards,
Pit

[1] http://www.objectteams.org
[2] http://www.objectteams.org/software.html#ROT

"Pit Capitain" <pit@capitain.de> wrote in message

   class Person
     def delegate_to(role)
       @seam.clear if @seam
       @seam = Seam.new do |s|
         s.instead_of(self, :describe) do role.describe end
         s.instead_of(role, :name) do self.name end
       end
     end
   end

Interesting. I'll give it some thought.

Would this require knowledge of the internal structure of role#describe? Or
would it be safe to do the following?
   (s.methods - Object.instance_methods).each {|m|
        s.instead_of(role, m.intern) do self.send(m) end
    }

Thanks.

itsme213 schrieb:

"Pit Capitain" <pit@capitain.de> wrote in message

  class Person
    def delegate_to(role)
      @seam.clear if @seam
      @seam = Seam.new do |s|
        s.instead_of(self, :describe) do role.describe end
        s.instead_of(role, :name) do self.name end
      end
    end
  end

Interesting. I'll give it some thought.

Would this require knowledge of the internal structure of role#describe? Or
would it be safe to do the following?
   (s.methods - Object.instance_methods).each {|m|
        s.instead_of(role, m.intern) do self.send(m) end
    }

You have to consider message parameters and blocks. If you want to pass them unchanged to the other object you could do it this way:

   (s.methods - Object.instance_methods).each do |m|
     s.instead_of(role, m) do |c|
       self.send(m, *c.args, &c.block)
     end
   end

The seam block is called with one parameter, a call object. Via this call object you can get access to the original method call, for example at its parameters and the block passed.

Regards,
Pit