Oddity with block argument passing

In my latest project, I was a bit surprised by the way arguments to
Proc.new were handled. Somehow an array which i passed in was
mysteriously lost and presented as a nil within the block I had
created.

If this is to be expected, I would have liked to see a mention of it
in the documentation. After reading the documentation more carefully,
I realized that if i would use Kernel.proc instead of Proc.new it
should do the same “except the resulting Proc objects check the number
of parameters passed”, which evidentially in my case also means that
the parameter actually goes through.

Wondering whether this was a bug or not, I tried out the latest CVS
version to see whether the behavior had changed or not. Indeed the
behavior was changed in the CVS version, but in a direction quite
opposite to what I had hoped for, since now both Proc.new and
Kernel.proc performs in the same way. (Eating up my array argument)

Kernel.lambda seems to work the way I want for all cases though and
thus using this will solve my problems, but I was curious whether this
difference between lambda and proc is intended, and also whether the
change of semantics from current to CVS was intended.

Below is an example which isn’t especially meaningful, but serves it’s
purpose to highlight the differences between the semantics of the
different approaches in different versions of ruby.

Constructs = [
lambda {|x, *y| [x, y]},
proc {|x, *y| [x, y]},
Proc.new {|x, *y| [x, y]}
]

puts “ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]”
Constructs.each{ |x| puts x[[]].inspect }

Below is the output of this script from the two versions of ruby where
I’ve tried it.

$ ruby proc_test.rb
ruby 1.8.3 (2005-09-21) [i686-linux]
[[], []]
[[], []]
[nil, []]

$ ruby-cvs proc_test.rb
ruby 1.9.0 (2005-12-20) [i686-linux]
[[], []]
[nil, []]
[nil, []]

Is this to be expected?

!g

[Gustav M. [email protected], 2005-12-20 21.40 CET]
[…]

I’ve tried it.
[nil, []]
[nil, []]

Compare:

def a x, *y
[x, y]
end

a [] # => [[], []]

x, *y = []

[x, y] # => [nil, []]

In one case, values are assigned as in normal assignment; in others, as
in
method parameter assignment. The “normal variable assignment” is to be
expected in normal blocks; the ones created with lambda use
parameter-like
assignment.

Is this to be expected?

Many people expect different things here, and you can find a lot of
discussions about this topic in the list archives.

HTH.

angus wrote:

Constructs.each{ |x| puts x[[]].inspect }
$ ruby-cvs proc_test.rb
end
assignment.

thanks for this explanation, now i really understand why there’s a
difference between the parameter-like assignment and normal variable
assignment.

they way you say it, it sounds as if the difference should be between
lambda and proc, but in 1.8.3 the difference is between Proc.new and
proc, does this mean that there is an issue with Kernel.proc in 1.8.3?

and i would also suggest changing the api-documation, allthough i don’t
know exactly i shall proceed to propose such a change. for Kernel.lambda
it currently states:

Equivalent to Proc.new, except the resulting Proc objects check the
number of parameters passed when called.

a better phrasing i think would be:

Equivalent to Proc.new, except the resulting Proc objects have
method-like-parameter-passing instead of the normal
expression-like-parameter-passing.

or something along those lines. personally i would think it’d be nice
with something more explaining the differences of the two, but the
api-documentation might not be the proper place for making this clear.

!g

Hi –

On Mon, 26 Dec 2005, Gustav M. wrote:

thanks for this explanation, now i really understand why there’s a difference
between the parameter-like assignment and normal variable assignment.

they way you say it, it sounds as if the difference should be between lambda
and proc, but in 1.8.3 the difference is between Proc.new and proc, does this
mean that there is an issue with Kernel.proc in 1.8.3?

proc and lambda are synonyms. Because it’s confusing for proc and
Proc.new to mean different things, Matz has said that proc is (will
be?) deprecated, so it will just be Proc.new and lambda.

David


David A. Black
[email protected]

“Ruby for Rails”, from Manning Publications, coming April 2006!