making a duck

E

Eric Mahurin

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 #
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
 
J

Jacob Fugal

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 #
methods, I could pass it something that looked just enough like
a String to work:
=20
alphabet =3D Object.duck:)[],proc{|i|?a+i},:size,proc{26})
=20
The implementation I came up with is this:
=20
class Object
def self.duck(*name_proc)
duck =3D self.new
duckclass =3D (class << duck;self;end)
while not name_proc.empty?
name,proc =3D name_proc.slice!(0,2)
duckclass.send:)define_method,name,&proc)
end
duck
end
end
=20
=20
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.


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 =3D {})
duck =3D self.new
duckclass =3D (class << duck; self; end)
methods.each do |name,proc|
duckclass.send:)define_method, name, &proc)
end
duck
end
end

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

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

Jacob Fugal
 
G

gabriele renzi

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?
 
D

David A. Black

Hi --

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 #
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.


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
 
R

Robert Klemme

Eric said:
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 #
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
 
E

Eric Mahurin

--- "David A. Black said:
Hi --

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 method. For example, if I
have a method that takes aString and uses the #size and #
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, it seems like there would already be something
out there to
do

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.


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
 
E

Eric Mahurin

--- Robert Klemme said:
Eric said:
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 #
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?


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
 
N

nobu.nokada

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 #
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"
 
E

Eric Mahurin

--- [email protected] said:
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 #
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"


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
 
N

nobu.nokada

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.
 
R

Robert Klemme

Eric said:
--- Robert Klemme said:
Eric said:
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 #
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?


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


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
 
E

Eric Mahurin

--- Robert Klemme said:
Eric said:
--- Robert Klemme said:
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
#
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?


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


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


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/
 
E

Eric Mahurin

--- [email protected] said:
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/
 
R

Robert Klemme

Eric said:
--- Robert Klemme said:
Eric said:
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
#
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?

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


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


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


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
 
R

Robert Klemme

Eric said:
--- [email protected] said:
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.

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
 
E

Eric Mahurin

--- Robert Klemme said:
Eric said:
--- [email protected] said:
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.

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.

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
 
R

Robert Klemme

Eric Mahurin said:
--- Robert Klemme said:
Eric said:
--- (e-mail address removed) 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.

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.

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".

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
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:

Kind regards

robert
 
E

Eric Mahurin

--- Robert Klemme said:
Why do you want rebind if the other approach is much simpler?

#instance_eval *always* rebinds self (and only self).

because you can get a handle on that rebound Proc. You might
want to pass it around or whatever.
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).
class_eval and instance_eval are not equivalent:

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


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
 
G

gabriele renzi

Eric Mahurin ha scritto:
--- Robert Klemme said:
Eric said:
--- (e-mail address removed) 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.

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.


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.

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.

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
 
E

Eric Mahurin

--- gabriele renzi said:
Eric Mahurin ha scritto:

... 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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,774
Messages
2,569,599
Members
45,175
Latest member
Vinay Kumar_ Nevatia
Top