Project

General

Profile

Actions

Bug #5328

closed

Splat args are treated wrongly in instance_exec and class_exec

Added by myronmarston (Myron Marston) almost 11 years ago. Updated about 8 years ago.

Status:
Rejected
Priority:
Normal
Target version:
-
ruby -v:
ruby 1.9.2p290 (2011-07-09 revision 32553) [x86_64-darwin10.8.0]
Backport:
[ruby-core:39562]

Description

This gist demonstrates the issue:

https://gist.github.com/1218664

On 1.8.7, instance_exec and class_exec treat splat block args the same as method splat args. On 1.9, it is treated differently and this is very unexpected.

Updated by ko1 (Koichi Sasada) over 10 years ago

  • Status changed from Open to Assigned
  • Assignee set to akr (Akira Tanaka)

Updated by akr (Akira Tanaka) about 8 years ago

  • Status changed from Assigned to Rejected

Ruby 1.9 changes block arguments behavior.
Non-lambda block arguments always expands single array.
(Ruby 1.8 expands sometimes.)

If you needs block arguments behaving as methods, use lambda.

% cat splat_args
def foo(arg_1, *arg_2)
  puts "Arguments received by method:"
  puts "arg_1: #{arg_1.inspect}"
  puts "arg_2: #{arg_2.inspect}"
end
foo([1, 2, 3])

puts

Class.class_exec([1, 2, 3]) do |arg_1, *arg_2|
  puts "Arguments received by class_exec:"
  puts "arg_1: #{arg_1.inspect}"
  puts "arg_2: #{arg_2.inspect}"
end

puts

instance_exec([1, 2, 3]) do |arg_1, *arg_2|
  puts "Arguments received by instance_exec:"
  puts "arg_1: #{arg_1.inspect}"
  puts "arg_2: #{arg_2.inspect}"
end

puts

Class.class_exec([1, 2, 3], &lambda do |arg_1, *arg_2|
  puts "Arguments received by class_exec(lambda):"
  puts "arg_1: #{arg_1.inspect}"
  puts "arg_2: #{arg_2.inspect}"
end)

puts

instance_exec([1, 2, 3], &lambda do |arg_1, *arg_2|
  puts "Arguments received by instance_exec(lambda):"
  puts "arg_1: #{arg_1.inspect}"
  puts "arg_2: #{arg_2.inspect}"
end)

% ruby-1.9.1p0 splat_args
Arguments received by method:
arg_1: [1, 2, 3]
arg_2: []

Arguments received by class_exec:
arg_1: 1
arg_2: [2, 3]

Arguments received by instance_exec:
arg_1: 1
arg_2: [2, 3]

Arguments received by class_exec(lambda):
arg_1: [1, 2, 3]
arg_2: []

Arguments received by instance_exec(lambda):
arg_1: [1, 2, 3]
arg_2: []

Updated by myronmarston (Myron Marston) about 8 years ago

Thanks for taking the time to explain.

This surprises me a bit because I've followed ruby development closely for a number of years and this is the first time I've heard of this particular proc vs lambda difference (I know of others like the difference in return and ArgumentError if a lambda is given the wrong number of args). It also seems very counterintuitive to me.

Is there a prior issue where this was discussed? I'd like to read up on it.

Thanks!

Updated by akr (Akira Tanaka) about 8 years ago

I can remember several documents.

  • The document of Proc#lambda?.
  • The thread from ruby-core:47453 "yield plus splat unwraps too much"
    (I don't recommend reading it in bugs.ruby-lang.org because messages are unintentionally formatted as markdown.)
  • ruby-dev:38795 (in Japanese)

Note that "always expands single array" was mistake.
The expantion also depends on the form of block arguments.

Updated by myronmarston (Myron Marston) about 8 years ago

Thanks. I'm still trying to wrap my head around it but that's quite helpful.

Actions

Also available in: Atom PDF