Gmail Calendar Documents Reader Web more »
Recently Visited Groups | Help | Sign in
Google Groups Home
making a duck
There are currently too many topics in this group that display first. To make this topic appear first, remove this option from another topic.
There was an error processing your request. Please try again.
flag
  Messages 1 - 25 of 27 - Collapse all  -  Translate all to Translated (View all originals)   Newer >
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Eric Mahurin  
View profile  
 More options Jun 6 2005, 12:00 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Tue, 7 Jun 2005 01:00:23 +0900
Local: Mon, Jun 6 2005 12:00 pm
Subject: making a duck
Regarding duck-typing... Is there an easy way make a "duck"?
i.e. an object that responds to enough methods to be an
acceptable argument to a certain methods.  For example, if I
have a method that takes aString and uses the #size and #[i]
methods, I could pass it something that looked just enough like
a String to work:

alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26})

The implementation I came up with is this:

class Object
    def self.duck(*name_proc)
        duck = self.new
        duckclass = (class << duck;self;end)
        while not name_proc.empty?
            name,proc = name_proc.slice!(0,2)
            duckclass.send(:define_method,name,&proc)
        end
        duck
    end
end

Is there another way to do this?  With all of the talk about
duck-typing, there would already be something out there to do
this.

__________________________________
Discover Yahoo!
Stay in touch with email, IM, photo sharing and more. Check it out!
http://discover.yahoo.com/stayintouch.html


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Jacob Fugal  
View profile  
 More options Jun 6 2005, 12:42 pm
Newsgroups: comp.lang.ruby
From: Jacob Fugal <lukf...@gmail.com>
Date: Tue, 7 Jun 2005 01:42:19 +0900
Local: Mon, Jun 6 2005 12:42 pm
Subject: Re: making a duck
On 6/6/05, Eric Mahurin <eric_mahu...@yahoo.com> wrote:

Well, my way isn't really different, and I actually wouldn't use
either "my" way or yours, but in the spirit of ruby I propose this
revision:

  class Object
    def self.duck(methods = {})
      duck = self.new
      duckclass = (class << duck; self; end)
      methods.each do |name,proc|
        duckclass.send(:define_method, name, &proc)
      end
      duck
    end
  end

  alphabet = Object.duck(
    :[] => proc{ |i| ?a+i },
    :size => proc{ 26 }
  )

I simply replaced the array with a hash. Looks a bit cleaner to me.

Jacob Fugal


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
gabriele renzi  
View profile  
 More options Jun 6 2005, 12:51 pm
Newsgroups: comp.lang.ruby
From: gabriele renzi <surrender...@remove-yahoo.it>
Date: Mon, 06 Jun 2005 16:51:21 GMT
Local: Mon, Jun 6 2005 12:51 pm
Subject: Re: making a duck
Eric Mahurin ha scritto:

> Is there another way to do this?  With all of the talk about
> duck-typing, there would already be something out there to do
> this.

There was some talk in the past about Object.new taking a block, which
imho would be useful for this. Meanwhile what about using Struct.new
with a block to define methods?

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
David A. Black  
View profile  
 More options Jun 6 2005, 12:57 pm
Newsgroups: comp.lang.ruby
From: "David A. Black" <dbl...@wobblini.net>
Date: Tue, 7 Jun 2005 01:57:14 +0900
Local: Mon, Jun 6 2005 12:57 pm
Subject: Re: making a duck
Hi --

I've always understood "duck typing" to refer to a particular approach
to the handling of method calls on objects, so I personally wouldn't
expect a to see a correlation between the amount of talk about duck
typing and this kind of technique.  Your technique looks to me like it
has more to do with the opposite end of the process: the preparation
and priming of an object, as a way of creating a situation favorable
to subsequent duck typing.  I don't think what you've got here stands
in any unique or special relation to duck typing; after all, from the
duck typing perspective, a method that an object got from its original
Class is just as much part of the object's behavior as a method the
object got extended with later.

In fact... your technique actually calls to mind Module#extend.  Do
you have a case where you'd prefer to do it the way you've done it
above, rather than defining the methods in a module and then extending
your object with it?

David

--
David A. Black
dbl...@wobblini.net


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Robert Klemme  
View profile  
 More options Jun 6 2005, 1:06 pm
Newsgroups: comp.lang.ruby
From: "Robert Klemme" <bob.n...@gmx.net>
Date: Mon, 6 Jun 2005 19:06:30 +0200
Local: Mon, Jun 6 2005 1:06 pm
Subject: Re: making a duck

Eric Mahurin wrote:
> Regarding duck-typing... Is there an easy way make a "duck"?
> i.e. an object that responds to enough methods to be an
> acceptable argument to a certain methods.  For example, if I
> have a method that takes aString and uses the #size and #[i]
> methods, I could pass it something that looked just enough like
> a String to work:

> alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26})

Why aren't you satisfied with

class Alpha
  def [](i) ?a+i end
  def size() 26 end
end
alphabet = Alpha.new

or

alphabet = Object.new
def alphabet.[](i) ?a+i end
def alphabet.size() 26 end

You can even squeeze that on one line if you feel the need for it.  I
mean, you don't generate those methods dynamically or get them from
somewhere else so why not just use the std approach?

Kind regards

    robert


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 6 2005, 1:50 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Tue, 7 Jun 2005 02:50:57 +0900
Local: Mon, Jun 6 2005 1:50 pm
Subject: Re: making a duck
--- "David A. Black" <dbl...@wobblini.net> wrote:

Correct.  I'm looking at the other side - making an object (a
"duck") that works well with a method using duck-typing.

> In fact... your technique actually calls to mind
> Module#extend.  Do
> you have a case where you'd prefer to do it the way you've
> done it
> above, rather than defining the methods in a module and then
> extending
> your object with it?

I was wanting to define the duck in-line with arbitrary procs
for the methods.  I'll give you a more concrete example using a
duck-typed method.  Take enum.include?(obj) for example.  It
searchs in enum something that matches obj using obj==element.
Let's say I wanted to match with obj===element or
obj.include?(element), etc.  I could do these:

enum.include?(Object.duck(:==,range.method(:===)))
enum.include?(Object.duck(:==,set.method(:include?)))
enum.include?(Object.duck(:==,hash.method(:[])))
enum.include?(Object.duck(:==,proc{|element|...}))

A special case that is very easily handled right now is if your
duck typing method takes an argument that only needs to respond
to [].  For example:

def scan_while(aHash)
    loop {
        ...
        aHash[element] or break
        ...
    }
end

scan_while(hash)
scan_while(proc{|element|...})
scan_while(set.method(:include?))
scan_while(range.method(:===))
scan_while(obj.method(:==))

__________________________________
Discover Yahoo!
Get on-the-go sports scores, stock quotes, news and more. Check it out!
http://discover.yahoo.com/mobile.html


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 6 2005, 2:51 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Tue, 7 Jun 2005 03:51:34 +0900
Local: Mon, Jun 6 2005 2:51 pm
Subject: Re: making a duck
--- Robert Klemme <bob.n...@gmx.net> wrote:

For the example I gave above, I think you are correct.  The
examples I gave in response to David Black are probably better
ones.  With those, a simple "def" won't cut it.  You need
define_method.  But, using define_method is cumbersome from an
object because you first need to make it have a singleton
class, then use "send" to access it from that class because it
it a private method.  Another solution to the problem of
"making a duck" would be to have a
Object#define_singleton_method:

class Object
    def define_singleton_method(name,&block)
        klass = (class << self;self;end)
        klass.send(:define_method,name,&block)
        self
    end
end

Then, for example, you could do this to make a set be useful
for a method that uses == for comparison:

seteq = Object.new.
    define_singleton_method(:==,&set.method(:include?))

I'm not sure why this isn't in Object right now.  It seems like
the rest of the *singleton_method* methods are there.

__________________________________
Discover Yahoo!
Find restaurants, movies, travel and more fun for the weekend. Check it out!
http://discover.yahoo.com/weekend.html


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
nobu.nok...@softhome.net  
View profile  
 More options Jun 6 2005, 9:39 pm
Newsgroups: comp.lang.ruby
From: nobu.nok...@softhome.net
Date: Tue, 7 Jun 2005 10:39:41 +0900
Local: Mon, Jun 6 2005 9:39 pm
Subject: Re: making a duck
Hi,

At Tue, 7 Jun 2005 01:00:23 +0900,
Eric Mahurin wrote in [ruby-talk:144691]:

> Regarding duck-typing... Is there an easy way make a "duck"?
> i.e. an object that responds to enough methods to be an
> acceptable argument to a certain methods.  For example, if I
> have a method that takes aString and uses the #size and #[i]
> methods, I could pass it something that looked just enough like
> a String to work:

> alphabet = Object.duck(:[],proc{|i|?a+i},:size,proc{26})

I'd posted a feature called `behavior' in [ruby-dev:25772].

  alphabet = Object.behaving(:[]) {|i|(?a+i).chr}
  p alphabet[20] #=> "u"

--
Nobu Nakada


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 6 2005, 10:59 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Tue, 7 Jun 2005 11:59:47 +0900
Local: Mon, Jun 6 2005 10:59 pm
Subject: Re: making a duck

Looks like 2 approaches to doing the same thing.  I do like the
hash interface a little better.  From your code that I read, it
looks like you can do this:

alphabet = Object.new.behaving(:[] => proc{|i|?a+i}, size:
proc{26})

I didn't know about the ":symbol => value" shortcut of "symbol:
value".  Or forgot about it.  Very nice in this situation.

Is there an advantage to having a separate Behavior class as
opposed the solution I had: making a singleton Object directly?

I think having something like this readily available would
promote more (interesting) uses of duck-typing.

__________________________________
Discover Yahoo!
Stay in touch with email, IM, photo sharing and more. Check it out!
http://discover.yahoo.com/stayintouch.html


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Robert Klemme  
View profile  
 More options Jun 7 2005, 3:51 am
Newsgroups: comp.lang.ruby
From: "Robert Klemme" <bob.n...@gmx.net>
Date: Tue, 7 Jun 2005 09:51:24 +0200
Local: Tues, Jun 7 2005 3:51 am
Subject: Re: making a duck

Btw, you can also use class eval:

class Object
    def define_singleton_method(name,&block)
        klass = (class << self;self;end).class_eval do
          define_method(name,&block)
        end
        self
    end
end

and also

o=Object.new
class <<o;self;end.class_eval do
  def bax() "bar" end
end
o.bax

> Then, for example, you could do this to make a set be useful
> for a method that uses == for comparison:

> seteq = Object.new.
>     define_singleton_method(:==,&set.method(:include?))

This does not work.  You cannot transfer a method from one class to
another:

09:14:01 [ruby]: cat define.rb

class Foo
  def test() bar() end
  def bar() "FOO::BAR" end
end

class Bar
  def bar() "BAR::BAR" end
end

bar = Bar.new
bar_kl = (class<<bar;self;end)
bar_kl.send(:define_method, :xxx, Foo.new.method(:test))
bar_kl.send(:public, :xxx)

bar.xxx()
09:15:33 [ruby]: ruby define.rb
define.rb:16:in `xxx': bind argument must be an instance of Foo
(TypeError)
        from define.rb:16

> I'm not sure why this isn't in Object right now.  It seems like
> the rest of the *singleton_method* methods are there.

Probably because it doesn't work - at least not completely the way you
like to have it.  Btw, and if you're borrowing implementations from other
classes then you can directly use an instance of that class...

Kind regards

    robert


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
nobu.nok...@softhome.net  
View profile  
 More options Jun 7 2005, 3:48 am
Newsgroups: comp.lang.ruby
From: nobu.nok...@softhome.net
Date: Tue, 7 Jun 2005 16:48:46 +0900
Local: Tues, Jun 7 2005 3:48 am
Subject: Re: making a duck
Hi,

At Tue, 7 Jun 2005 11:59:47 +0900,
Eric Mahurin wrote in [ruby-talk:144750]:

> Is there an advantage to having a separate Behavior class as
> opposed the solution I had: making a singleton Object directly?

To allow sharing same behavior.

--
Nobu Nakada


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 7 2005, 8:36 am
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Tue, 7 Jun 2005 21:36:10 +0900
Local: Tues, Jun 7 2005 8:36 am
Subject: Re: making a duck
--- Robert Klemme <bob.n...@gmx.net> wrote:

If you put an & in front of your "Foo.new.method(:test)" (like
what I did), or .to_proc it will work fine.

__________________________________
Discover Yahoo!
Use Yahoo! to plan a weekend, have fun online and more. Check it out!
http://discover.yahoo.com/


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 7 2005, 9:03 am
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Tue, 7 Jun 2005 22:03:41 +0900
Local: Tues, Jun 7 2005 9:03 am
Subject: Re: making a duck

--- nobu.nok...@softhome.net wrote:
> At Tue, 7 Jun 2005 11:59:47 +0900,
> Eric Mahurin wrote in [ruby-talk:144750]:
> > Is there an advantage to having a separate Behavior class
> as
> > opposed the solution I had: making a singleton Object
> directly?

> To allow sharing same behavior.

I'm not sure how much application this would have over the
conventional class definition approach.

At first I didn't think this would work because I thought you
wouldn't be able to create any instance variables using
define_method.  I thought any @ variables in a proc would refer
to the @ variable in the original context, but define_method
apparently rebinds them to the object.

__________________________________
Discover Yahoo!
Use Yahoo! to plan a weekend, have fun online and more. Check it out!
http://discover.yahoo.com/


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Robert Klemme  
View profile  
 More options Jun 7 2005, 10:39 am
Newsgroups: comp.lang.ruby
From: "Robert Klemme" <bob.n...@gmx.net>
Date: Tue, 7 Jun 2005 16:39:12 +0200
Local: Tues, Jun 7 2005 10:39 am
Subject: Re: making a duck

I always remind myself that the binding of "self" changes - even for each
method invocation.  This explains pretty good why this works as it should.

16:31:18 [ruby]: ruby x.rb
4
666
666
16:38:10 [ruby]: cat x.rb
o=Object.new
def o.size() 666 end
x="test"

class<<o;self;end.class_eval do
  define_method(:test) do
    puts x.size
    puts self.size
    puts size
  end
end

o.test
16:38:14 [ruby]:

Kind regards

    robert


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Robert Klemme  
View profile  
 More options Jun 7 2005, 10:32 am
Newsgroups: comp.lang.ruby
From: "Robert Klemme" <bob.n...@gmx.net>
Date: Tue, 7 Jun 2005 16:32:35 +0200
Local: Tues, Jun 7 2005 10:32 am
Subject: Re: making a duck

Darn, though I had the & in there.  However, there's another problem which
I originally wanted to demonstrate with this setup: methods might not
behave as one would expect:

16:31:16 [ruby]: cat define.rb

class Foo
  def test() bar() end
  def bar() "FOO::BAR" end
end

class Bar
  def bar() "BAR::BAR" end
end

bar = Bar.new
bar_kl = (class<<bar;self;end)
bar_kl.send(:define_method, :xxx, &Foo.new.method(:test))
bar_kl.send(:public, :xxx)

p bar.xxx()
16:31:16 [ruby]: ruby define.rb
"FOO::BAR"

Foo::test is still bound to Foo::bar and you probably would rather see
Bar::bar being called.

Kind regards

    robert


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 7 2005, 12:27 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Wed, 8 Jun 2005 01:27:20 +0900
Local: Tues, Jun 7 2005 12:27 pm
Subject: Re: making a duck
--- Robert Klemme <bob.n...@gmx.net> wrote:

define_method, instance_eval, class_eval, module_eval, and
maybe others seem to have this special ability - rebind the
meaning of self (but not locals) for a Proc.  This brings us
back to the topic I talked about earlier - unbind/rebind procs.
 It would be nice if we could do the same thing to a Proc that
these methods can do internally:

aProc.rebind_self(obj) -> aNewProc # rebind what self is

With this, "obj.instance_eval(&proc)" would be equivalent to
"proc.rebind_self(obj).call".  Other useful rebindings may be:

aProc.rebind_locals(binding) -> aNewProc
aProc.rebind_all(binding) -> aNewProc
# replace local variables with their current values
aProc.unbind_locals -> aNewProc

BTW, I don't see the value that class_eval and module_eval
provide over instance_eval.  classes and modules can be treated
like instances just like any other object.

__________________________________
Discover Yahoo!
Get on-the-go sports scores, stock quotes, news and more. Check it out!
http://discover.yahoo.com/mobile.html


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Christian Neukirchen  
View profile  
 More options Jun 7 2005, 12:31 pm
Newsgroups: comp.lang.ruby
From: Christian Neukirchen <chneukirc...@gmail.com>
Date: Wed, 8 Jun 2005 01:31:52 +0900
Local: Tues, Jun 7 2005 12:31 pm
Subject: Re: making a duck

gabriele renzi <surrender...@remove-yahoo.it> writes:
> Eric Mahurin ha scritto:

>> Is there another way to do this?  With all of the talk about
>> duck-typing, there would already be something out there to do
>> this.

> There was some talk in the past about Object.new taking a block, which
> imho would be useful for this. Meanwhile what about using Struct.new
> with a block to define methods?

Wow, this is nice... but where is it documented?

I used to use code like this until now:

class Foo < Struct.new(:all, :my, :fields)
  def mymethod
    # ...
  end
end

--
Christian Neukirchen  <chneukirc...@gmail.com>  http://chneukirchen.org


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 7 2005, 1:13 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Wed, 8 Jun 2005 02:13:32 +0900
Local: Tues, Jun 7 2005 1:13 pm
Subject: Re: making a duck
--- Christian Neukirchen <chneukirc...@gmail.com> wrote:

So is Struct.new(&block) equivalent to:

StructClass = Struct.new
StructClass.instance_eval(&block)
StructClass

So you could do this to make an object using == to map to ===
of a range.

alpha = ('a'..'z')
alphaeq =
Struct.new(:dummy){define_method(:==,&alpha.method(:===))}.new

Actually it looks like you can do the same thing with Class:

alpha = ('a'..'z')
alphaeq = Class.new{define_method(:==,&alpha.method(:===))}.new

This is still pretty verbose, but it seems like a descent
solution.  I'll use this until something better comes along.

__________________________________
Discover Yahoo!
Stay in touch with email, IM, photo sharing and more. Check it out!
http://discover.yahoo.com/stayintouch.html


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Robert Klemme  
View profile  
 More options Jun 7 2005, 1:14 pm
Newsgroups: comp.lang.ruby
From: "Robert Klemme" <bob.n...@gmx.net>
Date: Tue, 7 Jun 2005 19:14:06 +0200
Local: Tues, Jun 7 2005 1:14 pm
Subject: Re: making a duck

"Eric Mahurin" <eric_mahu...@yahoo.com> schrieb im Newsbeitrag
news:20050607162716.28170.qmail@web41115.mail.yahoo.com...

Why do you want rebind if the other approach is much simpler?
#instance_eval *always* rebinds self (and only self).

>  Other useful rebindings may be:

> aProc.rebind_locals(binding) -> aNewProc
> aProc.rebind_all(binding) -> aNewProc
> # replace local variables with their current values
> aProc.unbind_locals -> aNewProc

When do you think will unbind_locals be useful?  A proc typically needs some
of the variables bound.  As for the rebindings, I would prefer a general
mechanism to transfer state from one binding to another.  Then one could
implement all your rebind* methods in terms of that general mechanism plus
do more.  Alternatively one could think about conversion methods Binding <->
Hash.

> BTW, I don't see the value that class_eval and module_eval
> provide over instance_eval.  classes and modules can be treated
> like instances just like any other object.

class_eval and instance_eval are not equivalent:

>> class Foo;end
=> nil
>> Foo.class_eval do

?> def bar() "bar" end
>> end
=> nil
>> Foo.new.bar
=> "bar"
>> Foo.instance_eval do

?> def bax() "bax" end
>> end
=> nil
>> Foo.new.bax

NoMethodError: undefined method `bax' for #<Foo:0x10179ee0>
        from (irb):12


Kind regards

    robert


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 7 2005, 2:11 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Wed, 8 Jun 2005 03:11:18 +0900
Local: Tues, Jun 7 2005 2:11 pm
Subject: Re: making a duck
--- Robert Klemme <bob.n...@gmx.net> wrote:

because you can get a handle on that rebound Proc.  You might
want to pass it around or whatever.

> >  Other useful rebindings may be:

> > aProc.rebind_locals(binding) -> aNewProc
> > aProc.rebind_all(binding) -> aNewProc
> > # replace local variables with their current values
> > aProc.unbind_locals -> aNewProc

> When do you think will unbind_locals be useful?

As a replacement for many string evals - which are ugly,
inefficient, and possibly dangerous.  Many (most?) times that
you need to eval a string it is because you need to pull in
some local variables to help define the string to be evaled.
Here is the first example of a string eval in the 1.8 library I
found:

for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
                   LI OPTION tr th td ]
    methods += <<-BEGIN + nO_element_def(element) + <<-END
      def #{element.downcase}(attributes = {})
    BEGIN
      end
    END
end
eval(methods)

This could be replaced by:

for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
                   LI OPTION tr th td ]
    define_method(element.downcase.to_sym ,
        proc { |attributes={}|
            nO_element_def(element)
        }.unbind_locals # replace element with constant
    )
end

Much cleaner, huh?

> A proc
> typically needs some
> of the variables bound.  As for the rebindings, I would
> prefer a general
> mechanism to transfer state from one binding to another.
> Then one could
> implement all your rebind* methods in terms of that general
> mechanism plus
> do more.  Alternatively one could think about conversion
> methods Binding <->
> Hash.

Transferring locals might be pretty easy, but transferring the
meaning of self would be more difficult, I think.  At least
without making a new Binding (and then you'd still need a way
to rebind it to the original proc).

Interesting.  I assumed that since
class_eval/instance_eval/module_eval all returned the same
"self" that they did the same thing.  The only difference I see
is in "def <method> ...".  With class_eval, it defines instance
methods and with instance_eval, it defines class methods.
That's kind of strange.  Some kind of magic is going on here
other than the changing of self.

I was hoping that instance_eval could be used to define class
methods using #define_method, but #define_method does the same
with both - defines instance methods.  Anybody know of an
equivalent to #define_method for making class methods?  I
couldn't figure out any way to define a class method from a
proc - just out of curiosity.

__________________________________
Do you Yahoo!?
Yahoo! Mail - Helps protect you from nasty viruses.
http://promotions.yahoo.com/new_mail


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
gabriele renzi  
View profile  
 More options Jun 7 2005, 3:02 pm
Newsgroups: comp.lang.ruby
From: gabriele renzi <surrender...@remove-yahoo.it>
Date: Tue, 07 Jun 2005 19:02:37 GMT
Local: Tues, Jun 7 2005 3:02 pm
Subject: Re: making a duck
Eric Mahurin ha scritto:

nowhere, it seem. But I remebered it was discussed on ruby-core and
tried it :)

<snip>

> So is Struct.new(&block) equivalent to:

> StructClass = Struct.new
> StructClass.instance_eval(&block)
> StructClass

no, class_eval, and you have to submit at least one arg to Struct.new :/

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
gabriele renzi  
View profile  
 More options Jun 7 2005, 3:06 pm
Newsgroups: comp.lang.ruby
From: gabriele renzi <surrender...@remove-yahoo.it>
Date: Tue, 07 Jun 2005 19:06:22 GMT
Local: Tues, Jun 7 2005 3:06 pm
Subject: Re: making a duck
Eric Mahurin ha scritto:

I think of self as a dynamic variable, outside of lexical scope
and that makes me think..

> This brings us
> back to the topic I talked about earlier - unbind/rebind procs.
>  It would be nice if we could do the same thing to a Proc that
> these methods can do internally

.. would dynamic variables be enough? Christian Neukirchen has a nifty
implementation of them on his blog.

<snip>

> BTW, I don't see the value that class_eval and module_eval
> provide over instance_eval.  classes and modules can be treated
> like instances just like any other object.

if you define a method in a class_eval/module_eval block on object X
ruby will define it in instances of X while if you use instance_eval
you'd define the method on the object X

    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 7 2005, 4:09 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Wed, 8 Jun 2005 05:09:24 +0900
Local: Tues, Jun 7 2005 4:09 pm
Subject: Re: making a duck
--- gabriele renzi <surrender...@remove-yahoo.it> wrote:

> Eric Mahurin ha scritto:
> > This brings us
> > back to the topic I talked about earlier - unbind/rebind
> procs.
> >  It would be nice if we could do the same thing to a Proc
> that
> > these methods can do internally

> ... would dynamic variables be enough? Christian Neukirchen
> has a nifty
> implementation of them on his blog.

From what I saw, this didn't seem much different than another
space for global variables.  The main ability I was wanting was
to be able to replace local variables with their current value
in a proc.  I think this would make the ugly *eval(string)
methods rarely needed.  I just looked through the stdlib and
found almost every occurence of *eval(string) and found almost
every one looks kind of like this:

name = ...
var = ...
eval("def #{name} .... #{var} .... end")

This would work:

name = ...
var = ...
define_method(name.to_sym,proc{.... var ....}.unbind)

assuming that Proc#unbind replaced "var" with its current
value.

A define_class_method method would also be useful.  Otherwise
there would be no equivalent to the above when doing eval("def
self.#{name} .... end").

__________________________________
Discover Yahoo!
Find restaurants, movies, travel and more fun for the weekend. Check it out!
http://discover.yahoo.com/weekend.html


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Robert Klemme  
View profile  
 More options Jun 8 2005, 3:45 am
Newsgroups: comp.lang.ruby
From: "Robert Klemme" <bob.n...@gmx.net>
Date: Wed, 8 Jun 2005 09:45:31 +0200
Local: Wed, Jun 8 2005 3:45 am
Subject: Re: making a duck

I see.  Although I don't have a use case for this at hand and in fact
never missed that.  But that might be just my personal experience.

Not really (at least to my eyes).  Also, there are some issues:

 - I don't know what nO_element_def does exactly, but it will have to be
rewritten to not create a string with ruby code

 - Your version might be less efficient.

 - There might be subtle differences because "element" is pulled into the
closure

 - Also, unbind_locals will remove "element" from the procs bindings

Why do you think that self is special?  If there is a general mechanism to
transfer state (i.e. bindings) into a binding, any variable can be
rebound.  I imagine something like

proc.binding.bind(:self => whatever, :foo => "bar")
eval("self", proc.binding) # -> whatever
eval("foo", proc.binding) # -> "bar"

<snip/>

> Interesting.  I assumed that since
> class_eval/instance_eval/module_eval all returned the same
> "self" that they did the same thing.  The only difference I see
> is in "def <method> ...".  With class_eval, it defines instance
> methods and with instance_eval, it defines class methods.
> That's kind of strange.  Some kind of magic is going on here
> other than the changing of self.

Definitely.

> I was hoping that instance_eval could be used to define class
> methods using #define_method, but #define_method does the same
> with both - defines instance methods.  Anybody know of an
> equivalent to #define_method for making class methods?  I
> couldn't figure out any way to define a class method from a
> proc - just out of curiosity.

Since a class method is just an instance method of the class:

>> class Foo;end
=> nil
>> class <<Foo
>>   define_method(:bar) {"bar"}
>> end

=> #<Proc:0x10185860@(irb):7>

?> Foo.bar
=> "bar"


Thanks for the interesting exchange!

Kind regards

    robert


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Eric Mahurin  
View profile  
 More options Jun 8 2005, 12:30 pm
Newsgroups: comp.lang.ruby
From: Eric Mahurin <eric_mahu...@yahoo.com>
Date: Thu, 9 Jun 2005 01:30:53 +0900
Local: Wed, Jun 8 2005 12:30 pm
Subject: Re: making a duck
--- Robert Klemme <bob.n...@gmx.net> wrote:

Yep.  I wasn't paying attention very well.  Here is its
definition (this is from cgi.rb, BTW):

def nOE_element_def(element, append = nil)
    s = <<-END
        "<#{element.upcase}" + attributes.collect{|name, value|
            next unless value
            " " + CGI::escapeHTML(name) +
            if true == value
                ""
            else
                '="' + CGI::escapeHTML(value) + '"'
            end
        }.to_s + ">"
    END
    s.sub!(/\Z/, " +") << append if append
    s
end
def nO_element_def(element)
   nOE_element_def(element, <<-END)
       if block_given?
           yield.to_s + "</#{element.upcase}>"
       else
           ""
       end
   END
end

Here would be the evaluating (instead of generating) version:

def nOE_element_def(element,attributes)
    "<#{element.upcase}" + attributes.collect{|name, value|
        next unless value
        " " + CGI::escapeHTML(name) +
        if true == value
            ""
        else
            '="' + CGI::escapeHTML(value) + '"'
        end
    }.to_s + ">"
end
def nO_element_def(element,attributes)
    nOE_element_def(element,attributes) +
    if block_given?
        yield.to_s + "<#{element.upcase}>"
    else
        ""
    end
end

>  - Your version might be less efficient.

If you flatten the hierarchy, you should be able to get the
same efficiency:

for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
                   LI OPTION tr th td ]
  define_method(element.downcase.to_sym ,
    proc { |attributes={}|
      "<#{element.upcase}" + attributes.collect{|name, value|
        next unless value
        " " + CGI::escapeHTML(name) +
        if true == value
          ""
        else
          '="' + CGI::escapeHTML(value) + '"'
        end
      }.to_s + ">" +
      if block_given?
        yield.to_s + "<#{element.upcase}>"
      else
        ""
      end
    }.unbind_locals # replace element with constant
  )
end

>  - There might be subtle differences because "element" is
> pulled into the
> closure

>  - Also, unbind_locals will remove "element" from the procs
> bindings

I'm assuming that unbind_locals will simply replace any local
variables (external to the proc) with what their current value
is: element will become "HTML", "HEAD", "BODY", etc.

I was assuming that with local variables, you just be moving
the value from one binding to another - not aliasing.  The
problem is that you can't assign to "self".  If you really
could do the above, then this:

binding.bind(:self => whatever)

would be equivalent to:

self = whatever

I don't that would be a trivial thing to implement.  But, if
this "bind" created a new binding (i.e. non-destructive instead
of destructive), it would seem more feasible:

whateverBinding = binding.bind(:self => whatever)
whateverBinding.self.object_id==whatever.object_id

But then you are back to where you started - you still have a
bind the proc to a different binding (probably returning a new
proc).

> > Anybody know of an
> > equivalent to #define_method for making class methods?  I
> > couldn't figure out any way to define a class method from a
> > proc - just out of curiosity.

> Since a class method is just an instance method of the class:

> >> class Foo;end
> => nil
> >> class <<Foo
> >>   define_method(:bar) {"bar"}
> >> end

Thanks!  That works, but I wanted the proc to have visibility
to the local variables.  I think this would be more useful:

class Foo;end
(class<<Foo;self;end).send(:define_method,:bar) {"bar"}

> Thanks for the interesting exchange!

and thanks for your ideas.

.. back to my original topic - making a duck.  For my stuff, I
think I've decided to have 2 ways of doing it:

# make a duck using methods from obj
myDuck = obj.duck(newSym, oldSym, ...)

# make a duck using arbitrary procs
myDuck = duck(methSym => methProc, ...)

One of the applications I'm looking at now is for a method that
looks like this:

Cursor#scan(value)

where value is String/Array like.  All it needs is to respond
to #[int] which should return an object that responds to #==.
Although this #scan may look like it just matches to a verbatim
String/Array, you could also do something like this to match to
some digits:

# make == look like ===
digit = (?0..?9).duck(:==,:===)
# match to a string of 4 digits
# Proc responds to [] like a String/Array
cursor.scan(proc{|i|(i<4)? digit : nil})

Do people do things like this with duck-typing?  Or are most
just all talk.  Doing something like the above is where I see
the power.

__________________________________
Discover Yahoo!
Use Yahoo! to plan a weekend, have fun online and more. Check it out!
http://discover.yahoo.com/


    Reply to author    Forward  
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.
Messages 1 - 25 of 27   Newer >
« Back to Discussions « Newer topic     Older topic »

Create a group - Google Groups - Google Home - Terms of Service - Privacy Policy
©2009 Google