Injecting methods from one class into another

FWIW, in Javascript you can invoke a method defined anywhere with any scope that you wish. For example:

Object.prototype.toString = function(){
    return '['+this.constructor.name+' "'+this.name+'"]';
}

function Bird( inName ){
   this.name = inName;
   this.wings = 2;
}
Bird.prototype.fly = function(){
   if ( this.wings )
   {
     this.altitude += 100;
     alert( 'Look ma, ' + this + ' is flying!' );
   }
}

function Pig( inName ){
    this.name = inName;
}

var robin = new Bird( 'Tweeters' );
robin.fly(); // Look ma, [Bird "Tweeters"] is flying!

var super_pig = new Pig( 'Babe' );
super_pig.wings = 17;
robin.fly.call( super_pig ); // Look ma, [Pig "Babe"] is flying!
Bird.prototype.fly.call( super_pig ); // Look ma, [Pig "Babe"] is flying!

Perhaps it's the difference between a strongly-typed dynamic language, and a loosely-typed dynamic language. Perhaps it has no place in Ruby. But on occasion, I've enjoyed this flexibility in Javascript.

What makes Ruby not amenable to running arbitrary (but predefined) code against an arbitrary scope, and deciding only during the execution of each statement if the instance variables exist or not?

···

On Jan 25, 2005, at 9:09 AM, Gennady Bystritksy wrote:

I do not think what you want has anything to do with 'duck typing'. 'duck typing' only means that you can send a message to any object and if the object has a corresponding method it gets executed regardless of object type. It does not urge you to abandon the "normal" way of method definition for a class.

"George Moschovitis" <george.moschovitis@gmail.com> schrieb im Newsbeitrag
news:1106671017.848252.287620@c13g2000cwb.googlegroups.com...

Can anyone give me an example, where this #bind method is usefull? I
mean, you can only bind a Method back to an object of the original
method's Class or a Subclass. But such an object allready has this
method, so whats the point?
Am I missing something here?

Hm, maybe for caching:

@cached = lengthy_process_that_returns_an_unbound_method()

....

def treat(obj)
  @cached.bind(obj).call
end

Dunno whether that's more efficient than just remembering the symbol and
invoking the method via send...

Kind regards

    robert

George Moschovitis wrote:

Can anyone give me an example, where this #bind method is usefull? I
mean, you can only bind a Method back to an object of the original
method's Class or a Subclass. But such an object allready has this
method, so whats the point?

If you're subclass provides an overwritten version of the base method this trick still allows you to call the base one:

irb(main):012:0> Object.instance_method(:to_s).bind(2459).call
=> "#<Fixnum:0x1337>"
irb(main):013:0> Object.instance_method(:to_s).bind(nil).call
=> "#<NilClass:0x4>"

This can for example be used to implement a super() that skips over some of the inheritance chain members (see attachment.) or for sand boxes were you want to make sure that you are calling a secure method that is defined in Object and not an eventually overwritten version of it.

superjump.rb (797 Bytes)

George Moschovitis wrote:

I do not think what you want has anything to do with 'duck typing'.

Of course it has. Have a look at the following example:

class C1
attr_accessor :a

def a1
puts @a
end

def a2
puts 'hello'
end

class C2
attr_accessor :a
end

So for method C1#a1 the class C2 'quacks like a duck' (ie, it has the
attribute @a)

Your object doesn't quack like a duck. If it did it would have a method 'a1'. Your object has some of the same internal organs as a duck, which is both a gruesome image and not the same idea as duck typing. Duck typing is about interface not implementation. The implementation should be irrelevant ... only the interface matters.

R.

Here's a bit more thorough implementation which lets you do:

o = Object.new
o.cuckoo_bind Array, :size
o.size
=> 0

It also assumes you know what you are doing, ie. it relies on the
methods of the object which adopts the method.

I had to use metaclasses much more intensively than I wanted to (which
was "not at all"), for reasons not totally understood by me. (Just try
to strip them off, you'll see.) It can be modified to bind several
methods of the same class, but I won't do that now. Tested w/ 1.8.2.

···

On 2005-01-25, Robert Klemme <bob.news@gmx.net> wrote:

class Object
  def cast(target_class)
    copy = case target_class
      when Class; target_class.allocate
      when Module; dup.extend(target_class)
      else target_class.class.allocate
    end

    instance_variables.each do |var|
      copy.instance_variable_set(var, instance_variable_get(var))
    end

    copy
  end
end

Then you can create a tmp copy of an instance with all instance

variables

copied but a different class. So you can do
foo.cast(Bar).bar_method_to_be_called().

####################
class Object
  def metaclass
    class << self
      self
    end
  end
end

class Object
  def all_methods
    a=
    %w(public protected private).each {|x| a += send(x+"_methods") }
    a
  end
  def cuckoo_bind klass, methname
    methname = methname.to_s
    # We could ask for the (Unbound)Method directly as an argument
    # But then I can't see a better way to extract klass, methname than
    # meth.inspect[/: ([^#]*)#([^>]*)/]
    # klass = eval $1; methname = $2
    # and that's too hacky. It's a flaw in the API, imho.
    klass.instance_methods.include? methname or
      raise TypeError, "victim is unuseable"
    cuckoo = case klass
    when Class; cuckoo = klass.allocate
    when Module; cuckoo = Object.new; cuckoo.extend klass
    end
    # first we teach cuckoo what is easy to teach: our instance
    # variables
    instance_variables.each{|v|
      cuckoo.instance_variable_set v, instance_variable_get(v)
    }
    class << cuckoo
      def self.fetch data
        @fetched_data = data
      end
    end
    # cuckoo, we own you!
    warning_triggerers = %w(__id__ initialize __send__)
    bare_minimum = %w(fetch undef_method metaclass
instance_variable_get) + [methname] + warning_triggerers
    (all_methods - bare_minimum).each{ |m|
      cuckoo.metaclass.fetch m
      class << cuckoo
        begin
          undef_method @fetched_data
        rescue NameError
        end
      end
    }
    cuckoo.metaclass.fetch self
    # fly the cuckoo
    def cuckoo.method_missing *args, &bl
      metaclass.instance_variable_get(:@fetched_data).send *args, &bl
    end
    # we also have to learn making good use of cuckoo
    # it's hard to import local names to the metaclass' namespace
    class << self
      def self.fetch data
        @fetched_data = data
      end
    end
    @zoo ||= {}
    @zoo[methname] = cuckoo
    metaclass.fetch :methname => methname, :cuckoo => cuckoo
    class << self
      # define_method's block can't have block argument, hence the eval hack
      eval "def #{@fetched_data[:methname]}(*args, &bl)
        @zoo['#{@fetched_data[:methname]}'].#{@fetched_data[:methname]}(*args,&bl)
      end"
    end
    method methname
  end
end
####################

Gavin Kistner wrote:

I do not think what you want has anything to do with 'duck typing'. 'duck typing' only means that you can send a message to any object and if the object has a corresponding method it gets executed regardless of object type. It does not urge you to abandon the "normal" way of method definition for a class.

FWIW, in Javascript you can invoke a method defined anywhere with any scope that you wish. For example:

Object.prototype.toString = function(){
   return '['+this.constructor.name+' "'+this.name+'"]';
}

function Bird( inName ){
  this.name = inName;
  this.wings = 2;
}
Bird.prototype.fly = function(){
  if ( this.wings )
  {
    this.altitude += 100;
    alert( 'Look ma, ' + this + ' is flying!' );
  }
}

function Pig( inName ){
   this.name = inName;
}

var robin = new Bird( 'Tweeters' );
robin.fly(); // Look ma, [Bird "Tweeters"] is flying!

var super_pig = new Pig( 'Babe' );
super_pig.wings = 17;
robin.fly.call( super_pig ); // Look ma, [Pig "Babe"] is flying!
Bird.prototype.fly.call( super_pig ); // Look ma, [Pig "Babe"] is flying!

def method_missing( arg1, arg2=nil )
  if arg1.to_s =~ /([^=]*)=/
    instance_eval "@#{$1}= #{arg2};def #{$1}; @#{$1}; end"
  else
    super
  end
end

class Bird
   attr_accessor :wings
   def initialize( name )
     @name = name
     @wings = 2
   end

   def self.fly( arg=nil )
     obj = arg
     if obj.wings
       obj.instance_eval "@altitude ||=0"
       obj.instance_eval "@altitude += 100"
       puts "Look ma, #{obj.instance_eval '@name' } is flying!"
     end
   end

   def fly( arg=self )
     Bird.fly( arg )
   end
end

class Pig
   def initialize( name )
     @name = name
   end
end

robin = Bird.new( "Tweeters" )
robin.fly

super_pig = Pig.new( 'Babe' )
super_pig.wings = 17
robin.fly( super_pig )
Bird.fly( super_pig )

You can still achieve the same outcome, just not using the ECMA language syntax. JavaScript isn't the only prototype-based langauge out there. Flash ActionScript is much like this as well (and I believe nicer then JS).

Not having to mess with things like:
   Object.prototype.method.call
   Object.__prototype__.method.call
is a nice way to use class or module methods IMO, it's just much cleaner looking:
   Bird.prototype.fly.call( super_pig )
   Bird.fly( super_pig )

The nice thing about Ruby is that you DONT have to succumb to the behavior where new attributes will be created on the fly. If you want that functionality override method missing. Perhaps not every single Object out there needs this ability, but if you feel you need it somewhere then it's simple, easy and quick to add.

Zach

···

On Jan 25, 2005, at 9:09 AM, Gennady Bystritksy wrote:

Hm, maybe for caching:
@cached = lengthy_process_that_returns_an_unbound_method()
...
Dunno whether that's more efficient than just remembering the symbol

and

invoking the method via send...

Robert,

thank you for taking the time to answer my post.

However, I dont think that this is a usefull example. One could use a
simple
obj.class.class_eval("..") to achieve the same.

Dont you feel that allowing bind to attach methods only to objects that
already have this method (ie, obj.kind_of(class) == true) is strange?
George.

"George Moschovitis" <george.moschovitis@gmail.com> schrieb im Newsbeitrag
news:1106684784.267315.189500@z14g2000cwz.googlegroups.com...

> Hm, maybe for caching:
> @cached = lengthy_process_that_returns_an_unbound_method()
> ...
> Dunno whether that's more efficient than just remembering the symbol
and
> invoking the method via send...

Robert,

thank you for taking the time to answer my post.

However, I dont think that this is a usefull example. One could use a
simple
obj.class.class_eval("..") to achieve the same.

Dont you feel that allowing bind to attach methods only to objects that
already have this method (ie, obj.kind_of(class) == true) is strange?

Probably. But you can have several versions of a method with this:

class Foo
  def bar;"old" end
end

f = Foo.new
puts f.bar -> "old"
m = f.method(:bar).unbind
puts m.bind(f).call -> "old"

class Foo
  def bar;"new" end
end

puts f.bar -> "new"
puts m.bind(f).call -> "old"

Kind regards

    robert