On Apr 6, 2011, at 7:41 PM, Adam P. wrote:
On Thu, Apr 7, 2011 at 12:17 AM, 7stud – [email protected] wrote:
In case you didn’t know, procs and lambdas in ruby are a mess.
I knew, at least, ever since I read
http://innig.net/software/ruby/closures-in-ruby.rb
Interesting read but it seems like the author creates a bit more
confusion than is necessary.
That article repeats the common inaccuracy of treating blocks as
instances of Proc, but this is a category error. The two things are
related but not the same thing at all. I think it clarifies things to
view the term ‘block’ as a describing a syntactic element of a method
call and not as an instance of Proc. The syntactic element can get
reified into in a instance of Proc (or not) but the syntactic
representation is not itself an instance of Proc.
An analogy would be the difference between a literal integer and a
fixnum instance:
f1 = 16
f2 = 0xf
f3 = 0b10000
Here are three different syntactic representations of a single fixnum
reference. The sequence of characters ‘16’ is not an instance of
Fixnum, nor is ‘0xf’ or ‘0b10000’. The literals cause the runtime to
produce a reference to an instance of Fixnum but the syntactical
elements are not themselves objects.
Similarly for blocks:
3.times { puts ‘hip, hip, hooray!’ }
3.times do puts 'hip, hip, horray! }
The blocks are syntactically part of the method call to times and are
not themselves instances of Proc. And in the following:
proc { #block }
lambda { #block }
Proc.new { #block}
The ‘magic’ is happening in the method calls themselves and not in the
syntactic structure of the method calls, which is completely standard.
In the referenced article, the author starts off with:
But then I found out that a
function can’t accept multiple blocks – violating the principle that closures
can be passed around freely as values.
The author’s terminology is creating more complexity and perhaps
confusion than is warranted. It is true that a method call can only
have a single block in the same way that a method call can only have a
single argument list. They are both syntactical constructs of a method
call (blocks and argument lists).
It is not true that a method can not manipulate multiple closures
(instances of a Proc):
def compose(f1, f2, arg)
f1.call(f2.call(arg))
end
puts compose( lambda {|x| x * 2 }, lambda { |y| y + 1 }, 10 )
Ruby happens to provide a special syntax for creating and passing a
single closure to a method (i.e. the block syntax) but that doesn’t
prevent you from creating and passing multiple closures to a method if
that is what is desired.
The key point I’m trying to make is that it clarifies things to think of
‘block’ as a syntactical term and to think of ‘closure’ or ‘instance of
a Proc’ as the actual object that is being manipulated (i.e. passed
around, called, queried and so on).
When you look at a method that explicitly captures a block:
def iterate(a1, a2, &b)
[a1,a2].each(&b)
end
It is again important to think of ‘&’ as a syntactical construct in the
same way that the parens and commas are part of the syntax of the formal
argument list or of an actual method call. The & isn’t some strange
operator that converts or manipulates the proc instances referenced by
b, it is simply a syntactical marker for the block element of the method
syntax.
Gary W.