Forum: Ruby Functor Opinion

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Trans (Guest)
on 2006-03-19 13:16
(Received via mailing list)
So here's the Functor class:

  class Functor < BasicObject
    def initialize(*obj, &func)
      @obj = obj
      @func = func
    end
    def method_missing(op, *args)
      if @obj.empty?
        @func.call(op, *args)
      else
        @func.call(op, *(@obj + args))
      end
    end
  end

Anyone who has seen the older version of this cllas will notice that I
have added the *obj parameter. This allows the Functor to act like a
simple delegator too. But strictly speaking it isn't at all necessary
since one could just use the object(s) passed to the initialize
directly in the block. Eg.

  foo = 1
  Functor.new(foo) { |op, obj, *args| obj.send(op, *args) }

is the exact same as

  foo = 1
  Functor.new { |op, *args| foo.send(op, *args) }

The only time this really is a little more handy is when passing
'self', because of the ambiguity between contexts. Eg.

  Functor.new(self) { |op, obj, *args| obj.send(op, *args) }

vs.

  slf = self
  Functor.new { |op, *args| slf.send(op, *args) }

Not a big deal but there it is. Is there any other reason anyone can
think of that the *obj parameter is acctually needed or more convenient
vs. direct reference in the block itself? If not, is it worth keeping,
or should I just get rid of the *obj parameter altogether?

Settling that issue, I'd like to request that the Functor class be made
part of Ruby's standard library. It is simple, generic and generally
useful --I have had use for it myself on more than a few occasions now
across multiple projects.

Thanks,
T.
Robert K. (Guest)
on 2006-03-19 14:34
(Received via mailing list)
Trans <removed_email_address@domain.invalid> wrote:
>      else
>
>
> worth keeping, or should I just get rid of the *obj parameter
> altogether?
>
> Settling that issue, I'd like to request that the Functor class be
> made part of Ruby's standard library. It is simple, generic and
> generally useful --I have had use for it myself on more than a few
> occasions now across multiple projects.

I'm not the one who ultimately will decide whether something goes into
Ruby's standard lib or not.  But I have doubts in this case.  I cannot
recognize a clear cut task of this class; it's very generic and doesn't
really do much apart from propagating (delegating) arbitrary method
calls.
I'm not even sure that the name is appropriately chosen.  If one looks
at
the definition in Wikipedia at
http://en.wikipedia.org/wiki/Function_object
a functor needs at least the syntactic looks of a function.  In the case
of
Ruby, implementing #[] and / or #call seems to be a minimum requirement.

Can you elaborate a bit more the benefits and use cases of this class?
Thanks!

Kind regards

    robert
unknown (Guest)
on 2006-03-19 14:40
(Received via mailing list)
Hi --

On Sun, 19 Mar 2006, Trans wrote:

>      else
>
>
>  Functor.new(self) { |op, obj, *args| obj.send(op, *args) }
>
> vs.
>
>  slf = self
>  Functor.new { |op, *args| slf.send(op, *args) }

You shouldn't need to do that, though; self will be preserved from the
context of the block's creation:

     class C
     def f(&b)
       b.call
     end
   end

   C.new.f { puts self }  # main


David

--
David A. Black (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" chapters now available
from Manning Early Access Program! http://www.manning.com/books/black
Trans (Guest)
on 2006-03-19 16:15
(Received via mailing list)
> Can you elaborate a bit more the benefits and use cases of this class?
> Thanks!

Sure.

I'm aware that technically a Functor is nothing more than a first class
function. But Ruby already has a class for this, Proc (not to mention
Method). The class I present could more precisely be labeld a
"MetaFunctor". But since there's nothing of use to define as Functor in
Ruby I just dropped the "Meta" prefix. I'm all ears, if anyone has a
truly better name.

One could define #call and #[] for this class too, but we don't really
want to, because we want to keep as many methods available for passing
thru to method_missing as possibe. (Hence the subclass of BasicObject,
ie. BlankSlate).

I generally use it to create a separate method space for a class.
Here's an example of one place I've used it:

# facet/kernel/__meta__.rb

 begin
   require 'calibre/functor'
 rescue LoadError
   require 'facet/functor'
 end

 class Object

  # Returns a Functor that allows one to call any
  # Kernel method bound to self.
  #
  #   class A
  #     def object_id ; "OBTUSE" ; end
  #   end
  #
  #   c = C.new
  #   c.object_id             #=> "OBTUSE"
  #   c.__meta__.object_id    #=> 6664875832
  #
  def __meta__
    @__meta__ ||= Functor.new do |meth, *args|  # &blk|
      Kernel.instance_method(meth).bind(self).call(*args) # ,&blk)
    end
  end

 end

Additionally, the Functor can also be used as a quick and simple
delegator or proxy.

T.
Trans (Guest)
on 2006-03-19 16:19
(Received via mailing list)
> You shouldn't need to do that, though; self will be preserved from the
> context of the block's creation:
>
>     class C
>     def f(&b)
>       b.call
>     end
>   end
>
>   C.new.f { puts self }  # main

Thanks David I stand corrected on that point. I was confusiing it with
define_method blocks.

So even less reason to keep the *obj parameter? Hmm...if I added a
method to access those objects, then at least it could be used as
reference to what objects might be involved. That seems like a fair
usage.

T.
James G. (Guest)
on 2006-03-19 17:41
(Received via mailing list)
On Mar 19, 2006, at 12:33 AM, Trans wrote:

> Settling that issue, I'd like to request that the Functor class be
> made
> part of Ruby's standard library. It is simple, generic and generally
> useful --I have had use for it myself on more than a few occasions now
> across multiple projects.

Can you give example of where you used it?

James Edward G. II
Trans (Guest)
on 2006-03-19 17:54
(Received via mailing list)
> Can you give example of where you used it?

Check two posts back at 'facet/kernel/__meta__'.  Here's another for a
project I've been working on this week:

  class Program

    # ...

    def self.compile( yml, prg=nil )
      prg ||= Program.new

      sig = (class << prg; self; end)
      yml.each { |key, val|
        case val
        when RubyFn
          #val.out = val.out || key
          sig.class_eval {
            define_method( key ) { eval( val.code ) }
          }
        when Fn
          sig.class_eval {
            define_method( key ) { calc( val.code ) }
          }
        when Hash
          sig.class_eval {
            ftr = Functor.new { |op, *args| prg.send(op, *args) }
            res = compile( val, ftr )
            define_method( key ) { ftr }
          }
        when Type
          # do nothing
        else
          sig.class_eval {
            define_method( key ) { val }
          }
        end
      }

      return prg
    end

  end
This topic is locked and can not be replied to.