Project

General

Profile

Actions

Feature #3680

closed

Splatting calls to_ary instead of to_a in some cases

Added by tmat (Tomas Matousek) about 12 years ago. Updated over 11 years ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
[ruby-core:31676]

Description

=begin
In some cases to_ary is called to splat an array. Shouldn't to_a be always called?

class C
def respond_to? name
p name
false
end
end

p [1,*C.new]
p(*C.new)

x,y = C.new
p x,y

proc {|a,b| p [a,b] }.call(C.new)

ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-mingw32]
:to_a
[1, #<C:0x1984aa0>]
:to_a
#<C:0x1984900>
:to_ary
#<C:0x1984820>
nil
:to_ary
[#<C:0x1984680>, nil]
=end

Actions #1

Updated by runpaint (Run Paint Run Run) about 12 years ago

=begin
I addressed this as a footnote of http://ruby.runpaint.org/variables :

<<Note that :to_ary is sent rather than the :to_a used by the splat operator. In the former case, the programmer did not directly request that conversion take place so the message for implicit conversion is sent; in the latter, his use of the splat operator constitutes an explicit conversion, so the more liberal protocol is followed.>>

So, in your example #to_a is sent when the splat operator is used explicitly; #to_ary when it is used implicitly.
=end

Actions #2

Updated by tmat (Tomas Matousek) about 12 years ago

=begin
I see, so there is implicit and explicit splatting. The former uses to_ary the latter to_a.

So the splatting in the following code (in when clause) should use to_a since it is an explicit one, right? It attempts to call both to_ary and to_a though. I would expect it to call just to_a like any other explicit splatting.

class C
def respond_to? name
p name
false
end

def to_s
'c'
end
end

case
when *C.new;
end

output:
D:\temp\RubyParser>ruby19 -v x.rb
ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-mingw32]
:to_ary
:to_a

=end

Actions #3

Updated by runpaint (Run Paint Run Run) about 12 years ago

=begin
I don't have a 1.9.1 installed ATM, but on trunk/1.9.3 the following does indeed call #to_a. (#respond_to? isn't used in this case, no pun intended).

class C
def to_ary; p :ary; [:ary]; end
def to_a; p :a; [:a]; end
end
case
when *C.new
end

run@paint:/tmp → ruby -v x.rb
ruby 1.9.3dev (2010-06-05 trunk 28178) [i686-linux]
:a
=end

Actions #4

Updated by tmat (Tomas Matousek) about 12 years ago

=begin
OK, so this seems to be fixed. I haven't found more recent binaries for Windows than 1.9.1 so I can't test that.
So you're saying when *expr doesn't call respond_to? in 1.9.3? That looks like a bug unless splatting operations in general don't call respond_to? anymore in >1.9.1. They do in 1.9.1.
=end

Actions #5

Updated by runpaint (Run Paint Run Run) about 12 years ago

=begin

OK, so this seems to be fixed. I haven't found more recent binaries for Windows
than 1.9.1 so I can't test that.
So you're saying when *expr doesn't call respond_to? in 1.9.3? That looks like
a bug unless splatting operations in general don't call respond_to? anymore in
1.9.1. They do in 1.9.1.

They don't in general. The object is sent #to_a, if it responds--either because it defines a method by that name or #method_missing--the return value is splatted; otherwise [self] is used.
=end

Actions #6

Updated by tmat (Tomas Matousek) about 12 years ago

=begin
I'm confused. You're saying that in 1.9.2+ splatting operators don't call respond_to?(:to_a/:to_ary)? Almost all other conversions do call respond_to? first before calling the method itself. E.g.:

class C
def respond_to?(name)
p name
false
end
end

String(C.new) rescue p $!
Array(C.new)

ruby 1.9.1p378 (2010-01-10 revision 26273) [i386-mingw32]
:to_s
#<TypeError: can't convert C into String>
:to_ary
:to_a

So why should splatting, which is essentially a conversion to an array, be any different?
=end

Actions #7

Updated by runpaint (Run Paint Run Run) about 12 years ago

=begin
It's not. There's been a spec. change: instead of calling #respond_to?, we just try and call the method, rescuing NoMethodError. That is, #respond_to? will not be called by Array(), String(), Float(), etc. Splatting isn't special-cased. Besides, now we have #respond_to_missing?, an explicit conversion would have an overhead of two method calls... For background see revision 25556 and http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23738 .
=end

Actions #8

Updated by tmat (Tomas Matousek) about 12 years ago

=begin
Let's say I call File.open(C.new) where
class C
def to_str; "a.txt"; end
def method_missing name, *arg
raise NoMethodError
end
end

File.open tries at most 4 conversions: to_int, to_hash, to_path and to_str.
So if I understand this change well it means that File.open(C.new) calls method_missing(:to_int), method_missing(:to_hash) and method_missing(:to_path) throwing and rescueing 3 exceptions in order to find out that it should call to_str?

In other words there is no way how to detect that an object is convertible to_str w/o actually performing the conversion, calling to_str or method_missing(:to_str)?

=end

Actions #9

Updated by runpaint (Run Paint Run Run) about 12 years ago

=begin

o=Object.new
=> #Object:0x8b67d28
def o.method_missing(m,*)
p [method, m]
super
end
=> nil
File.open(o)
[:method_missing, :to_int]
[:method_missing, :to_hash]
[:method_missing, :to_path]
[:method_missing, :to_str]
TypeError: can't convert Object into String
from (irb):12:in initialize' from (irb):12:in open'
from (irb):12
from /usr/local/bin/irb:12:in `'

We should probably take this off-list to avoid cluttering the BTS any more; feel free to e-mail me.
=end

Actions #10

Updated by naruse (Yui NARUSE) almost 12 years ago

  • Status changed from Open to Rejected

=begin

=end

Actions

Also available in: Atom PDF