[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

passing method references in python & ruby

rpardee@gmail.com

1/18/2008 1:42:00 AM

Hey all,

Kind of an idle, syntax comparison question here...

In python, you can apparently pass method references around very
easily. So imagine you have these 2 functions defined:

def firstWay(arg1, arg2)
return 'Tastes great.'

def secondWay(arg1, arg2)
return 'Less filling.'

Then you can define a method that takes a method name as an argument,
and calls it just by throwing parens (and any expected arguments of
course) after it.

def doStuff(whichway, first_arg, second_arg)
return whichway(first_arg, second_arg)

So calling:

puts doStuff(firstWay, None, None)

Would result in 'Tastes great.'

What's the most graceful way to do this sort of thing in ruby? I
tried passing in e.g., firstWay.to_proc, but that got me a complaint
about not having enough arguments on the call. I can imagine doing,
e.g.,

first_pointer = Proc.new do |foo, bar|
return firstWay(foo, bar)
end

One for each alternate method & passing one of those in. I can also
imagine having doStuff take a block that would call the desired
function & yielding out to that. But neither of those are as pretty
as the python I think. Are those my best options in ruby, or is there
another way?

Thanks!

-Roy
18 Answers

Justin Collins

1/18/2008 4:13:00 AM

0

rpardee@gmail.com wrote:
> Hey all,
>
> Kind of an idle, syntax comparison question here...
>
> In python, you can apparently pass method references around very
> easily. So imagine you have these 2 functions defined:
>
> def firstWay(arg1, arg2)
> return 'Tastes great.'
>
> def secondWay(arg1, arg2)
> return 'Less filling.'
>
> Then you can define a method that takes a method name as an argument,
> and calls it just by throwing parens (and any expected arguments of
> course) after it.
>
> def doStuff(whichway, first_arg, second_arg)
> return whichway(first_arg, second_arg)
>
> So calling:
>
> puts doStuff(firstWay, None, None)
>
> Would result in 'Tastes great.'
>
> What's the most graceful way to do this sort of thing in ruby? I
> tried passing in e.g., firstWay.to_proc, but that got me a complaint
> about not having enough arguments on the call. I can imagine doing,
> e.g.,
>
> first_pointer = Proc.new do |foo, bar|
> return firstWay(foo, bar)
> end
>
> One for each alternate method & passing one of those in. I can also
> imagine having doStuff take a block that would call the desired
> function & yielding out to that. But neither of those are as pretty
> as the python I think. Are those my best options in ruby, or is there
> another way?
>
> Thanks!
>
> -Roy
>
>

Here is another way:

irb(main):001:0> def dostuff(whichway, arg1, arg2)
irb(main):002:1> send(whichway, arg1, arg2)
irb(main):003:1> end
=> nil
irb(main):004:0> def first_way(arg1, arg2)
irb(main):005:1> "tastes great"
irb(main):006:1> end
=> nil
irb(main):007:0> def second_way(arg1, arg2)
irb(main):008:1> "less filling"
irb(main):009:1> end
=> nil
irb(main):010:0> dostuff(:first_way, nil, nil)
=> "tastes great"
irb(main):011:0> dostuff(:second_way, nil, nil)
=> "less filling"
irb(main):012:0> "No! #{dostuff(:first_way, nil, nil).capitalize}!"
=> "No! Tastes great!"


-Justin

Robert Klemme

1/18/2008 3:39:00 PM

0

2008/1/18, Justin Collins <justincollins@ucla.edu>:
> rpardee@gmail.com wrote:
> > Hey all,
> >
> > Kind of an idle, syntax comparison question here...
> >
> > In python, you can apparently pass method references around very
> > easily. So imagine you have these 2 functions defined:
> >
> > def firstWay(arg1, arg2)
> > return 'Tastes great.'
> >
> > def secondWay(arg1, arg2)
> > return 'Less filling.'
> >
> > Then you can define a method that takes a method name as an argument,
> > and calls it just by throwing parens (and any expected arguments of
> > course) after it.
> >
> > def doStuff(whichway, first_arg, second_arg)
> > return whichway(first_arg, second_arg)
> >
> > So calling:
> >
> > puts doStuff(firstWay, None, None)
> >
> > Would result in 'Tastes great.'
> >
> > What's the most graceful way to do this sort of thing in ruby? I
> > tried passing in e.g., firstWay.to_proc, but that got me a complaint
> > about not having enough arguments on the call. I can imagine doing,
> > e.g.,
> >
> > first_pointer = Proc.new do |foo, bar|
> > return firstWay(foo, bar)
> > end
> >
> > One for each alternate method & passing one of those in. I can also
> > imagine having doStuff take a block that would call the desired
> > function & yielding out to that. But neither of those are as pretty
> > as the python I think. Are those my best options in ruby, or is there
> > another way?
> >
> > Thanks!
> >
> > -Roy
> >
> >
>
> Here is another way:
>
> irb(main):001:0> def dostuff(whichway, arg1, arg2)
> irb(main):002:1> send(whichway, arg1, arg2)
> irb(main):003:1> end
> => nil

#dostuff is really superfluous because the way you defined it it's
just an alias for #send.

> irb(main):004:0> def first_way(arg1, arg2)
> irb(main):005:1> "tastes great"
> irb(main):006:1> end
> => nil
> irb(main):007:0> def second_way(arg1, arg2)
> irb(main):008:1> "less filling"
> irb(main):009:1> end
> => nil
> irb(main):010:0> dostuff(:first_way, nil, nil)
> => "tastes great"
> irb(main):011:0> dostuff(:second_way, nil, nil)
> => "less filling"
> irb(main):012:0> "No! #{dostuff(:first_way, nil, nil).capitalize}!"
> => "No! Tastes great!"

So basically you would just do

send(:first_way, nil, nil)
send(:second_way, nil, nil)


However, if there are /many/ alternatives, then - depending on
circumstances - a Hash might be a better alternative:

algorithms = {
:first_way => lambda {|a,b| 'Tastes great.'},
:second_way => lambda {|a,b| 'Less filling'},
# more algorithms here...
}
# ...
puts algorithms[:first_way][nil, nil]
puts algorithms[:second_way][nil, nil]

Kind regards

robert

--
use.inject do |as, often| as.you_can - without end

rpardee@gmail.com

1/18/2008 5:45:00 PM

0

On Jan 17, 8:12 pm, Justin Collins <justincoll...@ucla.edu> wrote:
> rpar...@gmail.com wrote:
> > Hey all,
>
> > Kind of an idle, syntax comparison question here...
>
> > In python, you can apparently pass method references around very
> > easily. So imagine you have these 2 functions defined:
>
> > def firstWay(arg1, arg2)
> > return 'Tastes great.'
>
> > def secondWay(arg1, arg2)
> > return 'Less filling.'
>
> > Then you can define a method that takes a method name as an argument,
> > and calls it just by throwing parens (and any expected arguments of
> > course) after it.
>
> > def doStuff(whichway, first_arg, second_arg)
> > return whichway(first_arg, second_arg)
>
> > So calling:
>
> > puts doStuff(firstWay, None, None)
>
> > Would result in 'Tastes great.'
>
> > What's the most graceful way to do this sort of thing in ruby? I
> > tried passing in e.g., firstWay.to_proc, but that got me a complaint
> > about not having enough arguments on the call. I can imagine doing,
> > e.g.,
>
> > first_pointer = Proc.new do |foo, bar|
> > return firstWay(foo, bar)
> > end
>
> > One for each alternate method & passing one of those in. I can also
> > imagine having doStuff take a block that would call the desired
> > function & yielding out to that. But neither of those are as pretty
> > as the python I think. Are those my best options in ruby, or is there
> > another way?
>
> > Thanks!
>
> > -Roy
>
> Here is another way:
>
> irb(main):001:0> def dostuff(whichway, arg1, arg2)
> irb(main):002:1> send(whichway, arg1, arg2)
> irb(main):003:1> end
> => nil
> irb(main):004:0> def first_way(arg1, arg2)
> irb(main):005:1> "tastes great"
> irb(main):006:1> end
> => nil
> irb(main):007:0> def second_way(arg1, arg2)
> irb(main):008:1> "less filling"
> irb(main):009:1> end
> => nil
> irb(main):010:0> dostuff(:first_way, nil, nil)
> => "tastes great"
> irb(main):011:0> dostuff(:second_way, nil, nil)
> => "less filling"
> irb(main):012:0> "No! #{dostuff(:first_way, nil, nil).capitalize}!"
> => "No! Tastes great!"
>
> -Justin

Ah--that is nicer--thanks!

My momentary python envy (hmmm...) has now passed. ;-)

-Roy

Radoslaw Bulat

1/18/2008 7:07:00 PM

0

SW4gcHl0aG9uIHdoZW4geW91IHVzZSBtZXRob2QgbmFtZSB3aXRob3V0IHBhcmVudGhlc2lzZXMg
eW91IGdldAptZXRob2QgcmVmZXJlbmNlLiBJbiBSdWJ5IGl0IHdvbid0IHdvcmsgYmVhY3VzZSBt
ZXRob2QgY2FuIGJlIGNhbGxlZAp3aXRob3V0IHBhcmVudGhlc2lzZXMgKGFuZCBSdWJ5IHByb2dy
YW1tZXJzIGxvdmUgaXQgOikpLiBJZiB5b3Ugd2FudAp0byBnZXQgbWV0aG9kIHJlZmVyZW5jZSB5
b3UgY2FuIHVzZSBtZXRob2QoOnlvdV9tZXRob2RfbmFtZSkgYW5kIHlvdQpnZXQgcmVmZXJlbmNl
IHRvIE1ldGhvZCBpbnN0YW5jZS4gTGF0ZXIgeW91IGNhbiBqdXN0IGNhbGwgJ2NhbGwnCm1ldGhv
ZCBhbmQgcGFzcyBzb21lIHBhcmFtZXRlcnMuIERpcmVjdCB0cmFzbGF0aW9uIG9mIHlvdXIgcHJv
Z3JhbSB0bwpSdWJ5IGxvb2tzIGxpa2U6CgpkZWYgZmlyc3RXYXkoYXJnMSwgYXJnMikKICByZXR1
cm4gJ1Rhc3RlcyBncmVhdC4nCmVuZAoKZGVmIHNlY29uZFdheShhcmcxLCBhcmcyKQogIHJldHVy
biAnTGVzcyBmaWxsaW5nLicKZW5kCgpkZWYgZG9TdHVmZih3aGljaHdheSwgZmlyc3RfYXJnLCBz
ZWNvbmRfYXJnKQogIHJldHVybiB3aGljaHdheS5jYWxsKGZpcnN0X2FyZywgc2Vjb25kX2FyZykK
ZW5kCgpwdXRzIGRvU3R1ZmYobWV0aG9kKDpmaXJzdFdheSksIG5pbCwgbmlsKQoKCgotLSAKUmFk
b3OzYXcgQnWzYXQKCmh0dHA6Ly9yYWRhcmVrLmpvZ2dlci5wbCAtIG3zaiBibG9nCg==

Justin Collins

1/18/2008 7:12:00 PM

0

Rados3aw Bu3at wrote:
> In python when you use method name without parenthesises you get
> method reference. In Ruby it won't work beacuse method can be called
> without parenthesises (and Ruby programmers love it :)). If you want
> to get method reference you can use method(:you_method_name) and you
> get reference to Method instance. Later you can just call 'call'
> method and pass some parameters. Direct traslation of your program to
> Ruby looks like:
>
> def firstWay(arg1, arg2)
> return 'Tastes great.'
> end
>
> def secondWay(arg1, arg2)
> return 'Less filling.'
> end
>
> def doStuff(whichway, first_arg, second_arg)
> return whichway.call(first_arg, second_arg)
> end
>
> puts doStuff(method(:firstWay), nil, nil

Ah, that's the one I was looking for. Then you can do:

def doStuff(whichway, first_arg, second_arg)
whichway[first_arg, second_arg]
end


-Justin

Robert Klemme

1/19/2008 10:41:00 AM

0

On 18.01.2008 20:11, Justin Collins wrote:
> Radoslaw Bulat wrote:
>> In python when you use method name without parenthesises you get
>> method reference. In Ruby it won't work beacuse method can be called
>> without parenthesises (and Ruby programmers love it :)). If you want
>> to get method reference you can use method(:you_method_name) and you
>> get reference to Method instance. Later you can just call 'call'
>> method and pass some parameters. Direct traslation of your program to
>> Ruby looks like:
>>
>> def firstWay(arg1, arg2)
>> return 'Tastes great.'
>> end
>>
>> def secondWay(arg1, arg2)
>> return 'Less filling.'
>> end
>>
>> def doStuff(whichway, first_arg, second_arg)
>> return whichway.call(first_arg, second_arg)
>> end
>>
>> puts doStuff(method(:firstWay), nil, nil
>
> Ah, that's the one I was looking for. Then you can do:
>
> def doStuff(whichway, first_arg, second_arg)
> whichway[first_arg, second_arg]
> end

Yeah, but do you really consider

doStuff(method(:firstWay), nil, nil)

more concise than

send(:firstWay, nil, nil)

?

Cheers

robert

Robert Dober

1/19/2008 11:51:00 AM

0

On Jan 18, 2008 6:50 PM, rpardee@gmail.com <rpardee@gmail.com> wrote:

> My momentary python envy (hmmm...) has now passed. ;-)
Well that is good, but for the wrong reason :(

Our Rubyists where cheating on you as you had a first class object
called a function, and we were just using names.
Now there are no functions in Ruby so we cannot pass them on, we do
however have proc objects which would mimick what you have done in
Python
firstway =lambda{ |x| x+1}
otherway = lambda{ |x| x - 1}
def anyway away, anumber
away.call anumber
end

However the interesting and somewhat frustrating stuff starts with
methods which are first class objects in Ruby
class A
def first x; x+1 end
def second x; x-1 end
@f = instance_method :first
@s = instance_method :second
class << self
attr_reader :f, :s
end

def any method, number
method.bind( self ).call number
end
end

p A.new.any(A.f, 41)
p A.new.any(A.s,43)

Things are however a little bit trickier when it comes to binding
instance_methods
look at this code
class B
def b; 42 end
end

p B.instance_method(:b).bind(Object.new).call # :(((
I still fail to see the need for this restriction
Now lots of trickery is needed if you want to do things like these

module M
def m; 42 end
end

p Object.new.send(:extend, M).m

If you are interested in this stuff you might have a look at the
implementation of Traits in Ruby
http://rubyforge.org/projects/ru...
HTH
Robert

--
http://ruby-smalltalk.blo...

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Robert Dober

1/19/2008 1:25:00 PM

0

On Jan 19, 2008 1:59 PM, ts <decoux@moulon.inra.fr> wrote:
> >>>>> "R" == Robert Dober <robert.dober@gmail.com> writes:
>
> R> I still fail to see the need for this restriction
>
> Without this restriction you can write
>
> Array.instance_method(:[]).bind(Hash.new).call(0)
>
> and if you are not lucky ruby just crash.
Bad example of mine, what disturbs me is the following

not working:
Module::new{ def a; 42 end}.instance_method(:a).bind(Object.new).call

not working:
a=Modul::new{ def a; 42 end}.i_m :a
Object.module_eval{ define_method :x, a }

working;
module M
def m; 42 end
end

Object.module_eval{
include M
define_method :x, M.instance_method(:m)
}
p Object.new.x

and I thought we were all ducktypers :(

Robert
>
>
> Guy Decoux
>
>



--
http://ruby-smalltalk.blo...

---
Whereof one cannot speak, thereof one must be silent.
Ludwig Wittgenstein

Justin Collins

1/19/2008 7:45:00 PM

0

Robert Klemme wrote:
> On 18.01.2008 20:11, Justin Collins wrote:
>> RadosÅ?aw BuÅ?at wrote:
>>> In python when you use method name without parenthesises you get
>>> method reference. In Ruby it won't work beacuse method can be called
>>> without parenthesises (and Ruby programmers love it :)). If you want
>>> to get method reference you can use method(:you_method_name) and you
>>> get reference to Method instance. Later you can just call 'call'
>>> method and pass some parameters. Direct traslation of your program to
>>> Ruby looks like:
>>>
>>> def firstWay(arg1, arg2)
>>> return 'Tastes great.'
>>> end
>>>
>>> def secondWay(arg1, arg2)
>>> return 'Less filling.'
>>> end
>>>
>>> def doStuff(whichway, first_arg, second_arg)
>>> return whichway.call(first_arg, second_arg)
>>> end
>>>
>>> puts doStuff(method(:firstWay), nil, nil
>>
>> Ah, that's the one I was looking for. Then you can do:
>>
>> def doStuff(whichway, first_arg, second_arg)
>> whichway[first_arg, second_arg]
>> end
>
> Yeah, but do you really consider
>
> doStuff(method(:firstWay), nil, nil)
>
> more concise than
>
> send(:firstWay, nil, nil)
>
> ?
>
> Cheers
>
> robert

Clearly this is just a toy example to show options for how one might
call methods using variable names. If the doStuff method actually did
more stuff, then it would no longer be equivalent to send.


-Justin

Gregory Marton

2/24/2008 1:46:00 PM

0

What bugs me about ruby is that I can't do this
def add_one(n)
n + 1
end
[3,6,8].map(add_one)
=> [4,7,9]


I can't even do it more explicitly, because map won't take anything
other than a block:

irb(main):001:0> class A; def A.addone(x); x + 1; end; end
=> nil
irb(main):002:0> A.method(:addone)
=> #<Method: A.addone>
irb(main):003:0> [3,6,8].map{|x| x + 1}
=> [4, 7, 9]
irb(main):004:0> [3,6,8].map(A.method(:addone))
ArgumentError: wrong number of arguments (1 for 0)
from (irb):4:in `map'
from (irb):4
irb(main):005:0> [3,6,8].map(Proc.new{|x| A.method(:addone).call(x)})
ArgumentError: wrong number of arguments (1 for 0)
from (irb):5:in `map'
from (irb):5
irb(main):006:0> [3,6,8].map Proc.new{|x| A.method(:addone).call(x)}
ArgumentError: wrong number of arguments (1 for 0)
from (irb):6:in `map'
from (irb):6


Any of these would be defeating the purpose of brevity anyway. The best
I can do is to make a block that calls the proc I want:

irb(main):007:0> [3,6,8].map{|x| A.method(:addone).call(x)}
=> [4, 7, 9]

or more simply:
irb(main):008:0> [3,6,8].map{|x| A.addone(x)}
=> [4, 7, 9]

this seems a waste of keystrokes, a cognitive indirection, and probably
even a few processor cycles. Is there a way?

Grem
--
Posted via http://www.ruby-....