ruby-dev summary 24298-24353

S

SASADA Koichi

Hi all,

This is ruby-dev summary 24298-24353.


[ruby-dev:24302] Invoke Proc object with any method name

Nowake proposed that a Proc object should be invoked with
any method name like that:

m = Proc.new( :to_s ) { 'test1' }
p m.to_s # => 'test1'

This scheme is enabled with following code:

class MethodProc < Proc
def initialize( *method_name, &procedure )
super( &procedure )
m = Module.new
method_name.each do | i |
m.__send__( :define_method, i, &procedure )
end
self.extend( m )
end
end

He made a point that it is helphul that a Proc object can
be handled as polymorphic.

Matz amazed about this idea. This issue is still open.



# ruby-dev summary index:
# http://i.loveruby.net/en/ruby-dev-summary.html


See you at RubyConf2004.

Regards,
 
N

Nathaniel Talbott

[ruby-dev:24302] Invoke Proc object with any method name

Nowake proposed that a Proc object should be invoked with
any method name like that:

m = Proc.new( :to_s ) { 'test1' }
p m.to_s # => 'test1'

He made a point that it is helphul that a Proc object can
be handled as polymorphic.

Matz amazed about this idea.

Me too... I haven't found a place to use it since I read about it two
minutes ago, but it sends a tingle down my spine just thinking about
it. It is definitely polymorphic Ruby goodness. Maybe we can convince
Nowake to submit an RCR?

See you at RubyConf2004.

Looking forward to it...


Nathaniel
Terralien, Inc.

<:((><
 
R

Robert Klemme

SASADA Koichi said:
Hi all,

This is ruby-dev summary 24298-24353.


[ruby-dev:24302] Invoke Proc object with any method name

Nowake proposed that a Proc object should be invoked with
any method name like that:

m = Proc.new( :to_s ) { 'test1' }
p m.to_s # => 'test1'

This scheme is enabled with following code:

class MethodProc < Proc
def initialize( *method_name, &procedure )
super( &procedure )
m = Module.new
method_name.each do | i |
m.__send__( :define_method, i, &procedure )
end
self.extend( m )
end
end

He made a point that it is helphul that a Proc object can
be handled as polymorphic.

Matz amazed about this idea. This issue is still open.

Just out of curiosity (and because I can't read Japanese) is there any
advantage of using a Module over using the singleton class? As far as I
can see "self.extend(m)" creates the singleton class anyway.

Thinking a bit about this there could be numerous alternative approaches,
some of which might be more efficient. My suggestion would be this:

module Kernel
private
def MethodProc(*method_names, &b)
raise ArgumentError, "No block given" unless b

class <<b; self end.class_eval do
method_names.each {|m| alias_method m.to_sym, :call }
end

b
end
end


Kind regards

robert
 
P

Paul Brannan

Nowake proposed that a Proc object should be invoked with
any method name like that:

m = Proc.new( :to_s ) { 'test1' }
p m.to_s # => 'test1'

I know what the sample implementation does, but how would/should the
final version respond to:

p m.call()

Also, it took me a while to figure out what was meant by the above
code. What advantage does it give over:

m = Object.new
m.define_singleton_method:)to_s) { 'test1' }

(I know no such method exists, but I think it probably should...)

Paul
 
T

trans. (T. Onoma)

Me too... I haven't found a place to use it since I read about it two
minutes ago, but it sends a tingle down my spine just thinking about
it. It is definitely polymorphic Ruby goodness. Maybe we can convince
Nowake to submit an RCR?

Nice! I just ran into a possible use. Sometimes set_trace_func returns nil for
a binding. Passing this nil to methods expecting a binding causes further
exception handling needs. Blech! With the above I could pass on a "fake
binding" without having to create an actual FakeBinding class. Not bad.

Anyone see any issues with this?

Oh, and also, why is set_trace_func turning up with nil binding?

Thanks!
T.
 
T

trans. (T. Onoma)

Can you post a short sample that produces this?

Thanks for asking, since I may not have bothered to do this otherwise. It
looks like the binding is nil the same time that the class is false --on
'end' events. At least that's when it turns up with this example:

01 set_trace_func proc{ |e, f, l, m, b, k|
02 puts "#{e}, #{f}, #{l}, #{m}, #{k}" if ! b
03 }
04
05 module T
06 # setup
07 class Test
08 def initialize; @example = true; end
09 def test; "Okay!"; end
10 end
11 end
12
13 t = T::Test.new
14 t.test
15 t.test

Which returns:

end, t.rb, 7, , false
end, t.rb, 5, , false

I'm not sure why this would be. Isn't there always a context? Also I find the
line numbers odd (I added for easy reading), those mark where the 'class'
event occurs.

T.
 
R

Robert Klemme

Me too... I haven't found a place to use it since I read about it two
minutes ago, but it sends a tingle down my spine just thinking about it.
It is definitely polymorphic Ruby goodness. Maybe we can convince Nowake
to submit an RCR?

Possible uses are simple adaptors that adapt just one method like these:

1. Condition

ODD = MethodProc:)===) {|x| x % 2 != 0}
....

case n
when ODD
...
when ...
end


2. Fake Classes

Consider an object pool that needs a class instance as factory (i.e. to
create new instances). We can use a MethodProc instead:

class Pool
def initialize(cl)
@cl = cl
@pool = []
end

def get() @pool.shift || @cl.new end
def put(x) @pool << x end
end

pl = Pool.new( MethodProc:)new) { %w{a b c} } )


But the second example shows a more general pattern: what we need here is an
Adaptor because we might want to check the type of the object returned via
Class#=== to make sure only proper instances go into the Pool. In Ruby we
often use singleton methods to do method adptions, but there might be usages
where we don't want to change an instance. Here's a sample implementation:

class Adaptor
def initialize(obj, mappings)
@obj = obj
scl = class<<self; self end

# delegation of all public methods
obj.public_methods.each do |m|
m = m.to_sym

unless mappings[m]
scl.class_eval { define_method(m) { |*a| @obj.send(m,*a) } }
end
end

# remapping
mappings.each do |m,mapped|
case mapped
when Symbol
scl.class_eval { define_method(m) {|*a| @obj.send(mapped,*a) } }
when Proc
scl.class_eval { define_method(m,&mapped) }
else
raise ArgumentError, "Must be Proc or Symbol"
end
end
end
end

With this we can do
sample = %w{aa bb cc} => ["aa", "bb", "cc"]
fake_class = Adaptor.new(sample, :new => :dup, :=== => :==) => ["aa", "bb", "cc"]
x = fake_class.new => ["aa", "bb", "cc"]
"Is an instance of? #{fake_class === x}" => "Is an instance of? true"
x.id == sample.id
=> false

Now we can modify Pool#put to a more appropriate implementation:

class Pool
def put(x)
raise ArgumentError, "illegal type" unless @cl === x
@pool << x
end
end
pl = Pool.new fake_class
=> # said:
pl.get => ["aa", "bb", "cc"]
pl.put( pl.get ) => [["aa", "bb", "cc"]]
pl.put( "foo" )
ArgumentError: illegal type
from (irb):55:in `put'
from (irb):62
from (null):0ArgumentError: illegal type
from (irb):55:in `put'
from (irb):63
from (null):0

I'm not sure though whether there are many applications of this pattern in
Ruby because we have per instance method definitions with singleton classes.
What do others think?

Kind regards

robert
 
T

trans. (T. Onoma)

SASADA Koichi said:
Hi all,

This is ruby-dev summary 24298-24353.


[ruby-dev:24302] Invoke Proc object with any method name

Nowake proposed that a Proc object should be invoked with
any method name like that:

m = Proc.new( :to_s ) { 'test1' }
p m.to_s   # => 'test1'

This scheme is enabled with following code:

class MethodProc < Proc
  def initialize( *method_name, &procedure )
    super( &procedure )
    m = Module.new
    method_name.each do | i |
      m.__send__( :define_method, i, &procedure )
    end
    self.extend( m )
  end
end

He made a point that it is helphul that a Proc object can
be handled as polymorphic.

Matz amazed about this idea. This issue is still open.

http://jakarta.apache.org/commons/sandbox/functor/

T.
 
Y

Yukihiro Matsumoto

Hi,

In message "Re: ruby-dev summary 24298-24353"

|> Hmm, "fanctor". I like the name.
|
|Is a new class required? I think, Proc could add this feature and remain
|backward compatible.

I just said I liked the name. ;-)
I'm not yet sure if we need a new class.

matz.
 
T

trans. (T. Onoma)

Hi,

In message "Re: ruby-dev summary 24298-24353"

|> Hmm, "fanctor". I like the name.
|
|Is a new class required? I think, Proc could add this feature and remain
|backward compatible.

I just said I liked the name. ;-)
I'm not yet sure if we need a new class.

matz.

In that case you might want this:

# functor.rb

class Functor
def initialize(&func)
@func = func
end
def method_missing(op, *args)
@func.call(op, *args)
end
end

Shhh... Don't tell anyone. It's my favorite secret weapon ;)

T.

--
( o _ カラãƒ
// trans.
/ \ (e-mail address removed)

I don't give a damn for a man that can only spell a word one way.
-Mark Twain
 
A

Ara.T.Howard

In that case you might want this:

# functor.rb

class Functor
def initialize(&func)
@func = func
end
def method_missing(op, *args)
@func.call(op, *args)
end
end

Shhh... Don't tell anyone. It's my favorite secret weapon ;)

very cool.

-a
--
===============================================================================
| EMAIL :: Ara [dot] T [dot] Howard [at] noaa [dot] gov
| PHONE :: 303.497.6469
| A flower falls, even though we love it;
| and a weed grows, even though we do not love it.
| --Dogen
===============================================================================
 
R

Robert Klemme

Yukihiro Matsumoto said:
Hi,

In message "Re: ruby-dev summary 24298-24353"
|> Hmm, "fanctor". I like the name.
|
|Is a new class required? I think, Proc could add this feature and remain
|backward compatible.

I just said I liked the name. ;-)
I'm not yet sure if we need a new class.

What about the Adaptor idea I posted on 30.9. Somehow nobody seems to
have noticed. I'll repost the core part below.

robert
 
R

Robert Klemme

Robert Klemme said:
Yukihiro Matsumoto said:
Hi,

In message "Re: ruby-dev summary 24298-24353"


What about the Adaptor idea I posted on 30.9. Somehow nobody seems to
have noticed. I'll repost the core part below.

robert

Newsreader screwed up. Here it is:


But the second example shows a more general pattern: what we need here is
an
Adaptor because we might want to check the type of the object returned via
Class#=== to make sure only proper instances go into the Pool. In Ruby we
often use singleton methods to do method adptions, but there might be
usages
where we don't want to change an instance. Here's a sample
implementation:

class Adaptor
def initialize(obj, mappings)
@obj = obj
scl = class<<self; self end

# delegation of all public methods
obj.public_methods.each do |m|
m = m.to_sym

unless mappings[m]
scl.class_eval { define_method(m) { |*a| @obj.send(m,*a) } }
end
end

# remapping
mappings.each do |m,mapped|
case mapped
when Symbol
scl.class_eval { define_method(m) {|*a| @obj.send(mapped,*a) } }
when Proc
scl.class_eval { define_method(m,&mapped) }
else
raise ArgumentError, "Must be Proc or Symbol"
end
end
end
end

With this we can do
sample = %w{aa bb cc} => ["aa", "bb", "cc"]
fake_class = Adaptor.new(sample, :new => :dup, :=== => :==) => ["aa", "bb", "cc"]
x = fake_class.new => ["aa", "bb", "cc"]
"Is an instance of? #{fake_class === x}" => "Is an instance of? true"
x.id == sample.id
=> false
 
T

trans. (T. Onoma)

class Adaptor
def initialize(obj, mappings)
@obj = obj
scl = class<<self; self end

# delegation of all public methods
obj.public_methods.each do |m|
m = m.to_sym

unless mappings[m]
scl.class_eval { define_method(m) { |*a| @obj.send(m,*a) } }
end
end

# remapping
mappings.each do |m,mapped|
case mapped
when Symbol
scl.class_eval { define_method(m) {|*a| @obj.send(mapped,*a) } }
when Proc
scl.class_eval { define_method(m,&mapped) }
else
raise ArgumentError, "Must be Proc or Symbol"
end
end
end
end

With this we can do

=> ["aa", "bb", "cc"]

=> ["aa", "bb", "cc"]

=> ["aa", "bb", "cc"]

=> "Is an instance of? true"

=> false

Let me see if I understand this correctly. This is essentially a quick way to
create an adapter class based on a preexisting object. Is that right, or is
there more to it?

Also, what are you using this for? It seems cool enough, but I'm trying to get
a fix on it's uses.

T.
 
G

gabriele renzi

trans. (T. Onoma) ha scritto:
In that case you might want this:

# functor.rb

class Functor
def initialize(&func)
@func = func
end
def method_missing(op, *args)
@func.call(op, *args)
end
end

Shhh... Don't tell anyone. It's my favorite secret weapon ;)

Ok, I don't have an use for this, but, well, indeed very cool :)
 
R

Robert Klemme

trans. (T. Onoma) said:
class Adaptor
def initialize(obj, mappings)
@obj = obj
scl = class<<self; self end

# delegation of all public methods
obj.public_methods.each do |m|
m = m.to_sym

unless mappings[m]
scl.class_eval { define_method(m) { |*a| @obj.send(m,*a) } }
end
end

# remapping
mappings.each do |m,mapped|
case mapped
when Symbol
scl.class_eval { define_method(m) {|*a|
@obj.send(mapped,*a) } }
when Proc
scl.class_eval { define_method(m,&mapped) }
else
raise ArgumentError, "Must be Proc or Symbol"
end
end
end
end

With this we can do
sample = %w{aa bb cc}

=> ["aa", "bb", "cc"]
fake_class = Adaptor.new(sample, :new => :dup, :=== => :==)

=> ["aa", "bb", "cc"]
x = fake_class.new

=> ["aa", "bb", "cc"]
"Is an instance of? #{fake_class === x}"

=> "Is an instance of? true"
x.id == sample.id

=> false

Let me see if I understand this correctly. This is essentially a quick way
to
create an adapter class based on a preexisting object. Is that right, or
is
there more to it?

That's it exactly. Kind of an extension of Delegator.
Also, what are you using this for? It seems cool enough, but I'm trying to
get
a fix on it's uses.

Well, I presented one use, a fake class that implements important methods of
a class. OTOH, it might be more appropriate to create a new class from
scratch... In fact, this might be as easy:
fake_class = Class.new do ?> @sample = %w{a b c d}
def self.new() @sample.dup end
def self.===(x) @sample == x end
end
=> # said:
fake_class.new => ["a", "b", "c", "d"]
fake_class.new.id => 134638608
fake_class.new.id => 134620092
fake_class === fake_class.new
=> true

Hm...

robert
 
T

trans. (T. Onoma)

trans. (T. Onoma) ha scritto:

Ok, I don't have an use for this, but, well, indeed very cool :)

Here's one related to a recent thread:

class Object
def supers(klass=self.class.superclass)
raise ArgumentError if ! self.class.ancestors.include?(klass)
Functor.new do |meth, *args|
klass.instance_method(meth).bind(self).call(*args)
end
end
end

Hmm, maybe should cache the functor for efficiency.

T.
 

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,780
Messages
2,569,608
Members
45,244
Latest member
cryptotaxsoftware12

Latest Threads

Top