Functor Opinion


#1

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.


#2

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

#3

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


#4

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.


#5

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


#6

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.


#7

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