Project

General

Profile

Bug #8457

Function arguments: Is this intended?

Added by Anonymous about 4 years ago. Updated about 4 years ago.

Status:
Closed
Priority:
Normal
Target version:
-
ruby -v:
2.0.0
[ruby-core:55185]

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 } #=> ...

???

History

#1 [ruby-core:55188] Updated by matz (Yukihiro Matsumoto) about 4 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.

#2 [ruby-core:55191] Updated by phluid61 (Matthew Kerwin) about 4 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

#3 [ruby-core:55199] Updated by marcandre (Marc-Andre Lafortune) about 4 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?

#4 [ruby-core:55200] Updated by marcandre (Marc-Andre Lafortune) about 4 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?

#5 [ruby-core:55202] Updated by matz (Yukihiro Matsumoto) about 4 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.

#6 [ruby-core:55204] Updated by marcandre (Marc-Andre Lafortune) about 4 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.

Also available in: Atom PDF