Bug #8457

Function arguments: Is this intended?

Added by Boris Stitnicky 11 months ago. Updated 11 months ago.

[ruby-core:55185]
Status:Closed
Priority:Normal
Assignee:Yukihiro Matsumoto
Category:core
Target version:-
ruby -v:2.0.0 Backport:1.9.3: UNKNOWN, 2.0.0: UNKNOWN

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

???


Related issues

Related to Backport200 - Backport #8463: Proc auto-splat bug with named arguments Closed 05/30/2013

History

#1 Updated by Yukihiro Matsumoto 11 months 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 Updated by Matthew Kerwin 11 months 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 Updated by Marc-Andre Lafortune 11 months ago

  • Category set to core
  • Status changed from Closed to Open
  • Assignee set to 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 Updated by Marc-Andre Lafortune 11 months 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 Updated by Yukihiro Matsumoto 11 months 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 Updated by Marc-Andre Lafortune 11 months 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