Bug #8457
closedFunction arguments: Is this intended?
Description
a = [1, 2, x: 3]
a.tap { |*p, q| a.clear.concat p } #=> [1, 2]
but
a = [1, 2, x: 3]
a.tap { |*p, **q| a.clear.concat p } #=> [[...]]
and also
a = [1, 2]
a.tap { |*p| a.clear.concat p } #=> [[...]]
???
Updated by matz (Yukihiro Matsumoto) over 11 years ago
- Status changed from Open to Closed
I am not sure what you meant, but I am sure you are fooled by side-effect of #concat method.
a = [1, 2]
a.tap {|*p| # p is an array that wraps a i.e. p=[a]
a.clear # a is cleared; now p=[[]]
a.concat p # you concat p, that contains reference to a to a, make it circular
} # => a = [a]
This is not a bug.
Updated by phluid61 (Matthew Kerwin) over 11 years ago
=begin
boris_stitnicky (Boris Stitnicky) wrote:
a = [1, 2, x: 3]
a.tap { |*p, q| a.clear.concat p } #=> [1, 2]but
a = [1, 2, x: 3]
a.tap { |*p, **q| a.clear.concat p } #=> [[...]]and also
a = [1, 2]
a.tap { |*p| a.clear.concat p } #=> [[...]]???
Is this the problem?
a = [1,2,x:3]
a.tap { |*p,**q| puts "p=#{p.inspect}, q=#{q.inspect}" }
prints: p=[[1, 2, {:x=>3}]], q={}¶
expected: p=[1, 2], q={:x=>3}¶
as per:
a = [1,2,x:3]
def foo(*p,**q) puts "p=#{p.inspect}, q=#{q.inspect}"; end
foo *a
prints: p=[1, 2], q={:x=>3}¶
?
Note that the same behaviour occurs if the block has a (({**})) parameter.
(Tried on ruby 2.1.0dev (2013-04-24 trunk 40439) [x86_64-linux] )
=end
Updated by marcandre (Marc-Andre Lafortune) over 11 years ago
- Category set to core
- Status changed from Closed to Open
- Assignee set to matz (Yukihiro Matsumoto)
I'm wondering too if there isn't something strange?
I'd expect a proc to either do an implicit splat or not, but right now it looks for options before doing the implicit splat. Should it not do it after doing the implicit splat?
I thought that when a proc had an argument list with more than one element, it was the same to call it with a single array argument than with the same array splatted:
Proc{|a, ...| ... }.call([...]) == Proc{|a, ...}| ... }.call(*[...]) # => Because of implicit splat
But we have currently:
Proc.new{|a, *b, **c| p a, b, c}.call(1,2, bar: 3)
=> 1, [2], {:bar=>3} : OK¶
Proc.new{|a, *b, **c| p a, b, c}.call([1,2, bar: 3])
=> 1, [2, {:bar=>3}], {}: Expected same as above¶
Proc.new{|(a, *b), **c| p a, b, c}.call([1,2], bar: 3)
=> 1, [2], {:bar=>3} : OK¶
Proc.new{|(a, *b), **c| p a, b, c}.call([[1,2], bar: 3])
=> [1, 2], [{:bar=>3}], {}: Expected same as above¶
So, Matz, what do you think of these simplified examples?
Updated by marcandre (Marc-Andre Lafortune) over 11 years ago
As an additional note, this affects some methods of Enumerable when yielding multiple arguments.
For example:
def each; yield 1, 2, bar: 3; end
include Enumerable
each{|a, *b, **c| p a, b, c} # => 1, [2], {:bar => 3}: ok
detect{|a, *b, **c| p a, b, c} # => 1, [2, {:bar => 3}], {}: should be the same, no?
Updated by matz (Yukihiro Matsumoto) over 11 years ago
- Status changed from Open to Closed
I admit there's a bug which Matthew mentioned, but it's not described in the OP.
Do you mind if I close this, and ask you to resubmit as a new bug report for the record.
Matz.
Updated by marcandre (Marc-Andre Lafortune) over 11 years ago
Thanks.
I created #8463
matz (Yukihiro Matsumoto) wrote:
I admit there's a bug which Matthew mentioned, but it's not described in the OP.
Do you mind if I close this, and ask you to resubmit as a new bug report for the record.Matz.