Ruby-dev summary 24298-24353

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,

···

--
// SASADA Koichi at atdot dot net
//

[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'

<snip>

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.

<:((><

···

On Sep 29, 2004, at 09:38, SASADA Koichi wrote:

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

···

On Wed, Sep 29, 2004 at 10:38:55PM +0900, SASADA Koichi wrote:

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'

"SASADA Koichi" <ko1@atdot.net> schrieb im Newsbeitrag
news:20040929223720.2b31e9be%ko1@atdot.net...

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

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.

···

On Wednesday 29 September 2004 10:23 am, Nathaniel Talbott wrote:

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?

"Nathaniel Talbott" <nathaniel@talbott.ws> schrieb im Newsbeitrag news:2819AA48-1223-11D9-95A4-000A95CD7A8E@talbott.ws...

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

=> #<Pool:0x101b65d8 @cl=["aa", "bb", "cc"], @pool=>

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

pl.put( pl.get << "x" )

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

"SASADA Koichi" <ko1@atdot.net> schrieb im Newsbeitrag
news:20040929223720.2b31e9be%ko1@atdot.net...

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

Can you post a short sample that produces this?

Paul

···

On Thu, Sep 30, 2004 at 04:42:02AM +0900, trans. (T. Onoma) wrote:

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

Hi,

···

In message "Re: ruby-dev summary 24298-24353" on Fri, 1 Oct 2004 08:42:15 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:

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

Commons Functor - Overview

Hmm, "fanctor". I like the name.

              matz.

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.

···

On Wednesday 29 September 2004 04:45 pm, Paul Brannan wrote:

On Thu, Sep 30, 2004 at 04:42:02AM +0900, trans. (T. Onoma) wrote:
> Oh, and also, why is set_trace_func turning up with nil binding?

Can you post a short sample that produces this?

Is a new class required? I think, Proc could add this feature and remain
backward compatible.

T.

···

On Thursday 30 September 2004 08:17 pm, Yukihiro Matsumoto wrote:

Hi,

In message "Re: ruby-dev summary 24298-24353" > > on Fri, 1 Oct 2004 08:42:15 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:
>> > 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.
>
>Commons Functor - Overview

Hmm, "fanctor". I like the name.

Hi,

···

In message "Re: ruby-dev summary 24298-24353" on Fri, 1 Oct 2004 09:52:34 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:

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. :wink:
I'm not yet sure if we need a new class.

              matz.

Hi,

Sorry for being late.

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.

What is your concern. klass being false instead of nil? Is it a
problem for you? I could easily change it to nil, but have not really
been motivated.

Also, the "end" line does not have any AST node, so that the tracer
passes line numbers for corresponding start line (i.e. "class" for
this case).

              matz.

···

In message "Re: ruby-dev summary 24298-24353" on Thu, 30 Sep 2004 11:04:50 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:

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

T.

···

On Thursday 30 September 2004 09:07 pm, Yukihiro Matsumoto wrote:

Hi,

In message "Re: ruby-dev summary 24298-24353" > > on Fri, 1 Oct 2004 09:52:34 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:
>> 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. :wink:
I'm not yet sure if we need a new class.

              matz.

--
( o _ カラチ
// trans.
/ \ transami@runbox.com

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

"Yukihiro Matsumoto" <matz@ruby-lang.org> schrieb im Newsbeitrag
news:1096592771.410462.16363.nullmailer@x31.priv.netlab.jp...

Hi,

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

···

In message "Re: ruby-dev summary 24298-24353" > on Fri, 1 Oct 2004 09:52:34 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes:

Sorry for being late.

No rush. Way too much to do all 'round it seems. But thank you for getting
back to me.

What is your concern. klass being false instead of nil? Is it a
problem for you? I could easily change it to nil, but have not really
been motivated.

I don't understand why it doesn't return the class of the outer scope --and
it's binding too. In this case it would be TOPLEVEL_BINDING and class Object,
I believe.

Also, the "end" line does not have any AST node, so that the tracer
passes line numbers for corresponding start line (i.e. "class" for
this case).

Hmm. Well, guess there's no fix for that.

Thanks,
T.

···

On Tuesday 19 October 2004 09:39 pm, Yukihiro Matsumoto wrote:

very cool.

-a

···

On Fri, 1 Oct 2004, trans. (T. Onoma) wrote:

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

--

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

===============================================================================

"Robert Klemme" <bob.news@gmx.net> schrieb im Newsbeitrag
news:2s4gf0F1g0lreU1@uni-berlin.de...

"Yukihiro Matsumoto" <matz@ruby-lang.org> schrieb im Newsbeitrag
news:1096592771.410462.16363.nullmailer@x31.priv.netlab.jp...
> Hi,
>
>
> >> 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. :wink:
> 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

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

···

> In message "Re: ruby-dev summary 24298-24353" > > on Fri, 1 Oct 2004 09:52:34 +0900, "trans. (T. Onoma)" > <transami@runbox.com> writes:

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

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

Hi,

I don't understand why it doesn't return the class of the outer scope --and
it's binding too. In this case it would be TOPLEVEL_BINDING and class Object,
I believe.

trace_func receives 6 parameters:

  event: type of event which calls trace_func
  file: file name of the place of event
  line: line number of the place of event
  method: name of the method surrounding the place of event
  binding: binding at the place of event (if any)
  klass: class that defines calling method (for call event),
                or false value if event happened outside of any method

This in the current behavior, "method" and "klass" parameters are left
blank for the "end" event, caused by class/module statement outside of
methods. Do you want to change these? For any reason?

The "binding" parameter is bit more complicated. The "end" events are
caused just in the middle of scope transitions (class scope to outer
scope), so that I had hard time to determine which binding to return.
Besides that, all know usage of "end" event do not require any
information other than the event position, I haven't been motivated
much to change the behavior, making interpreter more complex.

              matz.

···

In message "Re: ruby-dev summary 24298-24353" on Wed, 20 Oct 2004 11:11:42 +0900, "trans. (T. Onoma)" <transami@runbox.com> writes: