[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Functor Opinion

Trans

3/19/2006 6:29:00 AM

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.

6 Answers

Robert Klemme

3/19/2006 12:33:00 PM

0

Trans <transfire@gmail.com> wrote:
> 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.

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



dblack

3/19/2006 12:40:00 PM

0

Trans

3/19/2006 2:11:00 PM

0

> 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

3/19/2006 2:16:00 PM

0

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

3/19/2006 3:42:00 PM

0

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 Gray II


Trans

3/19/2006 3:51:00 PM

0

> 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