Splat, #to_ary and #to_a

Hi!

I suppose this just qualifies as unexpected (by me) behaviour
but an odd thing happened when I wrote code like this:

[*"foo\nbar"] # => ["foo\n", "bar"]

Mocking out the call sequence for the splat, it seems that
it first checks for #respond_to? :to_ary and, if so, sends
it to the object--the surprising part was that if it does
NOT respond to :to_ary, the splat simply calls #to_a on its
subject.

The idea behind the code, of course, is to have a single
expression that either constructs an Array or reproduces
the current one from whatever object we are dealing with.
This behaviour makes doing so a tad less concise :slight_smile:

···

--
Posted via http://www.ruby-forum.com/.

Eero Saynatkari wrote:

Hi!

I suppose this just qualifies as unexpected (by me) behaviour
but an odd thing happened when I wrote code like this:

[*"foo\nbar"] # => ["foo\n", "bar"]

On the same topic, this is a strange parsing:

  stream.puts ( << obj).join("\n")

Above is the same as writing:

  stream.puts( << obj).join("\n")

···

--
Posted via http://www.ruby-forum.com/\.

Hi,

···

In message "Re: Splat, #to_ary and #to_a" on Mon, 18 Sep 2006 11:12:43 +0900, Eero Saynatkari <eero.saynatkari@kolumbus.fi> writes:

I suppose this just qualifies as unexpected (by me) behaviour
but an odd thing happened when I wrote code like this:

[*"foo\nbar"] # => ["foo\n", "bar"]

It's fixed in 1.9. 1.8 will remain as it is now for the sake of
compatibility.

              matz.

Hi!

I suppose this just qualifies as unexpected (by me) behaviour
but an odd thing happened when I wrote code like this:

[*"foo\nbar"] # => ["foo\n", "bar"]

Mocking out the call sequence for the splat, it seems that
it first checks for #respond_to? :to_ary and, if so, sends
it to the object--the surprising part was that if it does
NOT respond to :to_ary, the splat simply calls #to_a on its
subject.

The idea behind the code, of course, is to have a single
expression that either constructs an Array or reproduces
the current one from whatever object we are dealing with.
This behaviour makes doing so a tad less concise :slight_smile:

Can't you just test whether the object is an Array (or if it supports
the array methods you need)?

  x = "foo\nbar"
  (x.is_a?(Array) ? x : ) # => ["foo\nbar"]
  x = %w(a b c)
  (x.is_a?(Array) ? x : ) # => ["a", "b", "c"]

···

On 9/18/06, Eero Saynatkari <eero.saynatkari@kolumbus.fi> wrote:

--
Posted via http://www.ruby-forum.com/\.

--
- Simen

Yukihiro Matsumoto wrote:

Hi,

>I suppose this just qualifies as unexpected (by me) behaviour
>but an odd thing happened when I wrote code like this:
>
> [*"foo\nbar"] # => ["foo\n", "bar"]

It's fixed in 1.9. 1.8 will remain as it is now for the sake of
compatibility.

Thank you for clarification!

···

In message "Re: Splat, #to_ary and #to_a" > on Mon, 18 Sep 2006 11:12:43 +0900, Eero Saynatkari > <eero.saynatkari@kolumbus.fi> writes:

              matz.

--
Posted via http://www.ruby-forum.com/\.

Hmmmm,

Just what is the fix in 1.9.

Are you saying that
[*"foo\nbar"] #=> ["foo\nbar"]
in 1.9?

How about:
[*(1..4)]
which in 1.8.x produces [1, 2, 3, 4]

and which of these will change in 1.9?

def a(*arg)
     p arg
end

a("foo\nbar")
which in 1.8.4 prints ["foo\nbar"]

a((1..3))
prints [1, 2, 3, 4]
a(1..3)
prints [1..3]

a(1..3, "foo\nbar")
prints [1..3, "foo\nbar"]

a(*"foo\nbar")
prints ["foo\n", "bar"]

a(*(1..4))
prints [1, 2, 3, 4]

  *a = "foo\nbar"
  a gets ["foo\nbar"]
  *a = (1..4)
  a gets [1..4]
  *a = "foo\nbar", (1..3)
  a gets ["foo\nbar", 1..3]

I'm not sure that I see a consistent pattern here. But I have to say
that I think that the 1.8.x interpretations of

a(*"foo\nbar")
and
a(*(1..4))

both make sense since the caller is ASKING for the splat, and that
these two seem very similar to the
[*"foo\nbar"]
case which started this.

I've also always been surprised that String#to_a didn't produce an
array of single character strings, instead of splitting the string
into lines, but that's probably just a personal surprise, and I
wouldn't expect that to change.

···

On 9/17/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

Hi,

In message "Re: Splat, #to_ary and #to_a" > on Mon, 18 Sep 2006 11:12:43 +0900, Eero Saynatkari <eero.saynatkari@kolumbus.fi> writes:

>I suppose this just qualifies as unexpected (by me) behaviour
>but an odd thing happened when I wrote code like this:
>
> [*"foo\nbar"] # => ["foo\n", "bar"]

It's fixed in 1.9. 1.8 will remain as it is now for the sake of
compatibility.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Hi,

Just what is the fix in 1.9.

Are you saying that
[*"foo\nbar"] #=> ["foo\nbar"]
in 1.9?

Yes. And if you are curious you can try it by yourself.

How about:
[*(1..4)]
which in 1.8.x produces [1, 2, 3, 4]

Currently,

[1..4]

This may be an issue.

and which of these will change in 1.9?

def a(*arg)
    p arg
end

a("foo\nbar")
which in 1.8.4 prints ["foo\nbar"]

["foo\nbar"]

a((1..3))
prints [1, 2, 3, 4]

[1..3]

a(1..3)
prints [1..3]

[1..3]

a(1..3, "foo\nbar")
prints [1..3, "foo\nbar"]

[1..3, "foo\nbar"]

a(*"foo\nbar")
prints ["foo\n", "bar"]

["foo\nbar"]

a(*(1..4))
prints [1, 2, 3, 4]

[1..4]

*a = "foo\nbar"
a gets ["foo\nbar"]

["foo\nbar"]

*a = (1..4)
a gets [1..4]

[1..4]

*a = "foo\nbar", (1..3)
a gets ["foo\nbar", 1..3]

["foo\nbar", 1..3]

              matz.

···

In message "Re: Splat, #to_ary and #to_a" on Mon, 18 Sep 2006 12:28:18 +0900, "Rick DeNatale" <rick.denatale@gmail.com> writes:

Does the following happen only to me?

irb(main):001:0> def a(*arg)
irb(main):002:1> p arg
irb(main):003:1> end
=> nil
irb(main):004:0> a((1..3))
[1..3]
=> nil

Using ruby 1.8.4 (2006-04-14) [i386-mswin32].

Thanks,
Alvim.

···

On 9/18/06, Rick DeNatale <rick.denatale@gmail.com> wrote:

and which of these will change in 1.9?

def a(*arg)
     p arg
end

a("foo\nbar")
which in 1.8.4 prints ["foo\nbar"]

a((1..3))
prints [1, 2, 3, 4]

Hi,

>Just what is the fix in 1.9.
>
>Are you saying that
>[*"foo\nbar"] #=> ["foo\nbar"]
>in 1.9?

Yes. And if you are curious you can try it by yourself.

Is 1.9.0 good enough?, because I get

ruby1.9 -ve 'p [*"foo\nbar"]'
-->ruby 1.9.0 (2006-04-21) [i486-linux]
-->["foo\n", "bar"]

:frowning:

Robert

<SNIP>

···

On 9/18/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

In message "Re: Splat, #to_ary and #to_a" > on Mon, 18 Sep 2006 12:28:18 +0900, "Rick DeNatale" < > rick.denatale@gmail.com> writes:

                                                        matz.

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

Hi --

···

On Mon, 18 Sep 2006, Yukihiro Matsumoto wrote:

Hi,

In message "Re: Splat, #to_ary and #to_a" > on Mon, 18 Sep 2006 12:28:18 +0900, "Rick DeNatale" > <rick.denatale@gmail.com> writes:

>Just what is the fix in 1.9.
>
>Are you saying that
>[*"foo\nbar"] #=> ["foo\nbar"]
>in 1.9?

Yes. And if you are curious you can try it by yourself.

>How about:
>[*(1..4)]
>which in 1.8.x produces [1, 2, 3, 4]

Currently,

[1..4]

This may be an issue.

I've always thought it was convenient to have [*x] do the expanding
on x (including strings and ranges). But if it's going to disappear,
I think it should disappear consistently, so that * doesn't start
having a totally different meaning depending on the operand's class.

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Marcelo Alvim wrote:

···

On 9/18/06, Rick DeNatale <rick.denatale@gmail.com> wrote:

and which of these will change in 1.9?

def a(*arg)
     p arg
end

a("foo\nbar")
which in 1.8.4 prints ["foo\nbar"]

a((1..3))
prints [1, 2, 3, 4]

Does the following happen only to me?

irb(main):001:0> def a(*arg)
irb(main):002:1> p arg
irb(main):003:1> end
=> nil
irb(main):004:0> a((1..3))
[1..3]
=> nil

Using ruby 1.8.4 (2006-04-14) [i386-mswin32].

No, it the way it's supposed to be.

   a (1..3) #=> outputs: [1..3]
   a *(1..3) #=> outputs: [1, 2, 3]

Cheers,
Daniel

=== A reply to my questions ===

Thanks Matz!

Summarizing Matz' reply to my use cases:

1.9 here means the version of 1.9 as of Matz' reply:

Use case

Splat formal parameter.

def a(*arg)
     p arg
end

a("foo\nbar")
     1.8 ["foo\nbar"]
     1.9 ["foo\nbar"]

a((1..3))
     1.8 [1..3] Note: I think I had a typo on this one in my original post.
     1.9 [1..3]

a(1..3)
      1.8 [1..3]
      1.9 [1..3]

a(1..3, "foo\nbar")
       1.8 [1..3, "foo\nbar"]
       1.9 [1..3, "foo\nbar"]

So here, once my typo is accounted for, there's no difference.

Parallel assignment
*a = "foo\nbar"
     1.8 ["foo\nbar"]
     1.9 ["foo\nbar"]
*a = (1..4)
     1.8 [1..4]
     1.8 [1..4]
  *a = "foo\nbar", (1..3)
      1.8 ["foo\nbar", 1..3]
      1.9 ["foo\nbar", 1..3]

Again no changes here.

Splat's in array literal:
[*"foo\nbar"]
      1.8 ["foo\n", "bar"]
      1.9 ["foo\nbar"]

[*(1..4)]
      1.8 [1, 2, 3, 4]
      1.9 [1..4]

Here the difference seems to be that in 1.8 the splat had an effect
but in 1.9 it doesn't, at least for strings and ranges. Personally
this seems like the wrong direction to me, but that's a gut reaction.

The reason I THINK that it's wrong is that it looks like it seems to
ignore the explicit request represented by the *. Now I can
understand that it might be confusing in a case like this:

def b(str)
    [*str]
end

b("a") #=> ["a"]
b("foo\nbar") #=> ["foo\n", "bar"]

But I'm not convinced that it's a net positive change. Convincable,
but not convinced.

method call with splat argument

a(*"foo\nbar")
       1.8 ["foo\n", "bar"]
       1.9 ["foo\nbar"]

a(*(1..4))
     1.8 [1, 2, 3, 4]
     1.9 [1..4]

Here again, it looks like an explicit request to splat the parameter
is being ignored in 1.9.

Note that this very case came up recently in a discussion of expanding
an array in the arguments to Array#values_at like the method does
itself for range arguments.

Sorry I haven't installed 1.9 myself, so I'm wondering if something like

  (1..10).to_a.values_at(3..5)

still works the same way as it does in 1.8 (returning [4, 5, 6]) or
throws an exception saying that it can't convert a range to an integer
similar to the way 1.8 does with:
  (1..10).to_a.values_at([3, 4, 5])

···

On 9/18/06, Yukihiro Matsumoto <matz@ruby-lang.org> wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Hi --

> Hi,
>
> >Just what is the fix in 1.9.
> >
> >Are you saying that
> >[*"foo\nbar"] #=> ["foo\nbar"]
> >in 1.9?
>
> Yes. And if you are curious you can try it by yourself.
>
> >How about:
> >[*(1..4)]
> >which in 1.8.x produces [1, 2, 3, 4]
>
> Currently,
>
> [1..4]
>
> This may be an issue.

I've always thought it was convenient to have [*x] do the expanding
on x (including strings and ranges). But if it's going to disappear,
I think it should disappear consistently, so that * doesn't start
having a totally different meaning depending on the operand's class.

I have found, and it seems it was not a common concern, that Range and <=>
and #succ
are too closly coupled, but that is OT,

I think it would be a nice opportunity to define the protocol for *, cleanly
and giving the community the opportunity to express the fors and againsts
about potential implementations, well the good ol' ML stuff :wink:

Personally I thought the #to_a protocol is perfect, but #to_a is not.

Cheers
Robert

David

···

On 9/18/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

On Mon, 18 Sep 2006, Yukihiro Matsumoto wrote:
> In message "Re: Splat, #to_ary and #to_a" > > on Mon, 18 Sep 2006 12:28:18 +0900, "Rick DeNatale" > > <rick.denatale@gmail.com> writes:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

We could always have a "hyper-fatsplat" >>*<< [1]. Then it could do
everything at once, plus feed your cats when you go on vacation. :wink:

[1] see Perl6's "hyper-fatarrow" -
http://www.nntp.perl.org/group/perl.perl6.language/25946

Regards,
Jordan

Hi,

···

In message "Re: Splat, #to_ary and #to_a" on Mon, 18 Sep 2006 17:54:32 +0900, "Robert Dober" <robert.dober@gmail.com> writes:

Is 1.9.0 good enough?, because I get

ruby1.9 -ve 'p [*"foo\nbar"]'
-->ruby 1.9.0 (2006-04-21) [i486-linux]

When we talk about 1.9, the date matters. And we encourage to try the
most recent version from CVS HEAD. It's 2006-09-18 today.

              matz.

unknown wrote:

Hi --

>in 1.9?

This may be an issue.

I've always thought it was convenient to have [*x] do the expanding
on x (including strings and ranges). But if it's going to disappear,
I think it should disappear consistently, so that * doesn't start
having a totally different meaning depending on the operand's class.

I dunno--you have to use Range#to_a explicitly elsewhere so I
feel that would be consistent here also. I think my preferred
solution would be for splat to use #to_ary and leave everything
else explicit.

Of course this is a very limited application of the splat operator.

···

On Mon, 18 Sep 2006, Yukihiro Matsumoto wrote:

David

--
Posted via http://www.ruby-forum.com/\.

Rick DeNatale wrote:

Sorry I haven't installed 1.9 myself, so I'm wondering if something like

  (1..10).to_a.values_at(3..5)

still works the same way as it does in 1.8 (returning [4, 5, 6]) or
throws an exception saying that it can't convert a range to an integer
similar to the way 1.8 does with:
  (1..10).to_a.values_at([3, 4, 5])

$ ruby19 -v && ruby19 -e "p (1..10).to_a.values_at(3..5)"
ruby 1.9.0 (2006-09-19) [i686-linux]
[4, 5, 6]

Regards,
Jordan

We could always have a "hyper-fatsplat" >>*<< [1]. Then it could do
everything at once, plus feed your cats when you go on vacation. :wink:

Noo, noo, Matz please do not listen to him, I have two dogs.
Make it feed dogs, PLEASE

Robert

[1] see Perl6's "hyper-fatarrow" -

···

On 9/18/06, MonkeeSage <MonkeeSage@gmail.com> wrote:

Re: Pair of lists => list of pairs? - nntp.perl.org

Regards,
Jordan

--
Deux choses sont infinies : l'univers et la bêtise humaine ; en ce qui
concerne l'univers, je n'en ai pas acquis la certitude absolue.

- Albert Einstein

Yukihiro Matsumoto wrote:

Hi,

>Is 1.9.0 good enough?, because I get
>>
>ruby1.9 -ve 'p [*"foo\nbar"]'
>-->ruby 1.9.0 (2006-04-21) [i486-linux]

When we talk about 1.9, the date matters. And we encourage to try the
most recent version from CVS HEAD. It's 2006-09-18 today.

              matz.

So does this mean that Why's excellent talk at RailsConf Europe is
already out of date?

···

In message "Re: Splat, #to_ary and #to_a" > on Mon, 18 Sep 2006 17:54:32 +0900, "Robert Dober" <robert.dober@gmail.com> writes:

Hi --

unknown wrote:

Hi --

>in 1.9?

This may be an issue.

I've always thought it was convenient to have [*x] do the expanding
on x (including strings and ranges). But if it's going to disappear,
I think it should disappear consistently, so that * doesn't start
having a totally different meaning depending on the operand's class.

I dunno--you have to use Range#to_a explicitly elsewhere so I
feel that would be consistent here also.

My point is that I don't want to have to use Range#to_a explicitly but
not String#to_a, nor the other way around. In other words, I don't
want *(0...10) to do one thing and *"a\nb" to do another. It's not
that I'm hung up on consistency per se (lots of cool Ruby things come
from inconsistency :slight_smile: but I don't like things where there are two
cases and no clear reason why, so you have to memorize them
individually.

David

···

On Tue, 19 Sep 2006, Eero Saynatkari wrote:

On Mon, 18 Sep 2006, Yukihiro Matsumoto wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org