[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

idiom I've not seen before

Rob Saul

2/7/2008 3:55:00 AM


I came across this :
elements.sort_by(&:position).each
in something I've taken over. I thought sort_by
took a block. Obviously I'm missing something.
Can anyone shed some light on this trick?

~Rob


12 Answers

Rob Biedenharn

2/7/2008 4:04:00 AM

0

On Feb 6, 2008, at 10:55 PM, Rob Saul wrote:
> I came across this :
> elements.sort_by(&:position).each
> in something I've taken over. I thought sort_by
> took a block. Obviously I'm missing something.
> Can anyone shed some light on this trick?
>
> ~Rob


You've found Symbol#to_proc

That line is equivalent to:

elements.sort_by {|e| e.send(:position) }.each

The "something" is a Rails project, isn't it?

== vendor/rails/activesupport/lib/active_support/core_ext/symbol.rb ==
class Symbol
# Turns the symbol into a simple proc, which is especially useful
for enumerations. Examples:
#
# # The same as people.collect { |p| p.name }
# people.collect(&:name)
#
# # The same as people.select { |p| p.manager? }.collect { |p|
p.salary }
# people.select(&:manager?).collect(&:salary)
def to_proc
Proc.new { |*args| args.shift.__send__(self, *args) }
end
end


I don't know how you can send additional arguments however.

-Rob

Rob Biedenharn http://agileconsult...
Rob@AgileConsultingLLC.com



Jeremy Kemper

2/7/2008 4:07:00 AM

0

On 2/6/08, Rob Saul <wyrd@code-gnomemad.org> wrote:
> I came across this :
> elements.sort_by(&:position).each
> in something I've taken over. I thought sort_by
> took a block. Obviously I'm missing something.
> Can anyone shed some light on this trick?

Sure. &:position == :position.to_proc == proc { |element, *args|
element.position(*args) }

So elements.sort_by(&:position) is shorthand for sorting the elements
by position.

jeremy

Rob Saul

2/7/2008 4:14:00 AM

0

Jeremy Kemper wrote:
>
> Sure. &:position == :position.to_proc == proc { |element, *args|
> element.position(*args) }
>
> So elements.sort_by(&:position) is shorthand for sorting the elements
> by position.
>
> jeremy

thanks to both Jeremy and Rob for the enlightenment. And
yes, it is a Rails project.



Martin DeMello

2/7/2008 5:05:00 AM

0

On Feb 7, 2008 4:14 AM, Rob Saul <wyrd@code-gnomemad.org> wrote:

> thanks to both Jeremy and Rob for the enlightenment. And
> yes, it is a Rails project.

Also, I believe Symbol.to_proc is making it into 1.9

martin

Thomas Wieczorek

2/7/2008 5:14:00 AM

0

On Thu, Feb 7, 2008 at 6:04 AM, Martin DeMello <martindemello@gmail.com> wrote:
>
> Also, I believe Symbol.to_proc is making it into 1.9
>

Yes, it is in.
Raganwald has a good blog entry about it, he also mentions
String#to_proc:
http://weblog.raganwald.com/2007/11/fun-with-symbolt...

Ryan Davis

2/7/2008 5:16:00 AM

0


On Feb 6, 2008, at 20:04 , Rob Biedenharn wrote:

> You've found Symbol#to_proc
>
> That line is equivalent to:
>
> elements.sort_by {|e| e.send(:position) }.each

Buyer beware:

#!/usr/local/bin/ruby -w

# # of iterations = 10000
# user system total real
# null_time 0.000000 0.000000 0.000000 ( 0.001561)
# map 0.880000 0.000000 0.880000 ( 0.878500)
# to_proc 2.790000 0.000000 2.790000 ( 2.799291)

# # of iterations = 100000
# user system total real
# null_time 0.020000 0.000000 0.020000 ( 0.013951)
# map 8.730000 0.010000 8.740000 ( 8.766693)
# to_proc 27.960000 0.030000 27.990000 ( 28.001288)

require 'benchmark'

class Symbol
def to_proc
Proc.new { |*args| args.shift.__send__(self, *args) }
end
end

a = (1..100).to_a

raise "stupid" unless a.map { |n| n.to_s } == a.map(&:to_s)

max = (ARGV.shift || 1_000_000).to_i

puts "# of iterations = #{max}"
Benchmark::bm(20) do |x|
x.report("null_time") do
for i in 0..max do
# do nothing
end
end

x.report("map") do
for i in 0..max do
a.map { |n| n.to_s }
end
end

x.report("to_proc") do
for i in 0..max do
a.map(&:to_s)
end
end
end


botp

2/7/2008 5:35:00 AM

0

On Feb 7, 2008 1:16 PM, Ryan Davis <ryand-ruby@zenspider.com> wrote:
>
> Buyer beware:
>
> # # of iterations = 10000
> # user system total real
> # null_time 0.000000 0.000000 0.000000 ( 0.001561)
> # map 0.880000 0.000000 0.880000 ( 0.878500)
> # to_proc 2.790000 0.000000 2.790000 ( 2.799291)
>
> # # of iterations = 100000
> # user system total real
> # null_time 0.020000 0.000000 0.020000 ( 0.013951)
> # map 8.730000 0.010000 8.740000 ( 8.766693)
> # to_proc 27.960000 0.030000 27.990000 ( 28.001288)

that will change in ruby1.9 since to_proc is builtin.
eg, a run in windows,

C:\ruby1.9\bin>.\ruby.exe test.rb 1_000
# of iterations = 1000
user system total real
null_time 0.000000 0.000000 0.000000 ( 0.000000)
map 0.203000 0.000000 0.203000 ( 0.203000)
to_proc 0.156000 0.000000 0.156000 ( 0.172000)

C:\ruby1.9\bin>.\ruby.exe test.rb 10_000
# of iterations = 10000
user system total real
null_time 0.016000 0.000000 0.016000 ( 0.015000)
map 1.937000 0.000000 1.937000 ( 2.515000)
to_proc 1.610000 0.000000 1.610000 ( 1.954000)

C:\ruby1.9\bin>.\ruby.exe test.rb 100_000
# of iterations = 100000
user system total real
null_time 0.328000 0.000000 0.328000 ( 0.328000)
map 19.344000 0.000000 19.344000 ( 24.953000)
to_proc 17.296000 0.015000 17.311000 ( 18.016000)

not bad, imho.
kind regards -botp

Phlip

2/7/2008 5:36:00 AM

0

Jeremy Kemper wrote:

> Sure. &:position == :position.to_proc == proc { |element, *args|
> element.position(*args) }
>
> So elements.sort_by(&:position) is shorthand for sorting the elements by
> position.

How would you pass the *args in?? They don't seem to fit on either side
of the &, which is "special" in argument passing syntax...

--
Phlip

Phrogz

2/7/2008 5:57:00 PM

0

On Feb 6, 8:55 pm, Rob Saul <w...@code-gnomemad.org> wrote:
> I came across this :
> elements.sort_by(&:position).each

Loosely-related aside:

I've been learning Io[1] recently. Io (like Lisp, I gather) allows
lazy evaluation of method arguments. In Ruby terms, this would mean
that I can write something like this:

# Ruby-esque pseudo-code; neither Io nor Ruby
class Array
def select
result = []
self.each{ |el| result << el if el.sendArg(0) }
result
end
end

my_array.select( isCool? )
my_array.select( > 5 )
my_array.select( roughlyEquals( jim.newSize ) )

In Io, the "isCool?" method/message isn't (necessarily) evaluated when
you call the select method. Instead, you can perform some
introspection on the parsed message tree for each argument and choose
to ignore it, change it to a string, or send it as a message to any
object you want.

To be clear, in the above, the "isCool?" message/method would be send/
invoked on each array element. Or each element would be sent a
">( 5 )" message.

The Symbol#to_proc technique is clever, but not quite as clean as
being able to write (in Io):
elements sortBy( position )
elements map( * 2 )
elements select( size > 5 )


This same ability in Io allowed me to add a debugging method "p" (in
homage of Ruby) that labels a value with the exact call you made. For
example:

# In Io with my custom method (not Ruby)
p( gk )
#=> gk is Person_0x4de0d8:
#=> name = "Gavin Kistner"
#=> nick = "Phrogz""

p( gk name )
#=> gk name is Gavin Kistner

p( gk nick size )
#=> gk nick size is 6



[1] http://www.iolan...

Clifford Heath

2/7/2008 10:39:00 PM

0

Phrogz wrote:
> I've been learning Io[1] recently. Io (like Lisp, I gather) allows
> lazy evaluation of method arguments.
....
> In Io, the "isCool?" method/message isn't (necessarily) evaluated when
> you call the select method.

This is known as "call by name", as opposed to by reference or by value.
It was, more than anything, the single thing that caused the most difficulty
for the authors of Algol68 optimising compilers :-).

Niklaus Wirt once joked that Europeans (who know how to pronounce his name)
called him by name, whereas Americans called him by value (nickel's worth).
Maybe apocryphal, but funny :-).

Clifford Heath.