Koan question

Working through the Ruby koans and came up with a question.

With:
  array = [:peanut, :butter, :and, :jelly]

Then this yeilds true:
  assert_equal [], array[4,0]

But so does this:
  assert_equal nil, array[5,0]

Why is [4,0] and empty array and [5,0] nil?

Leam

···

--
Mind on a Mission

You're using the shorthand for "slice" on the array class.

Ruby docs have some more examples that may help you to work out why it
behaves like it does...

···

On Thu, Nov 13, 2014 at 4:52 PM, leam hall <leamhall@gmail.com> wrote:

Working through the Ruby koans and came up with a question.

With:
  array = [:peanut, :butter, :and, :jelly]

Then this yeilds true:
  assert_equal , array[4,0]

But so does this:
  assert_equal nil, array[5,0]

Why is [4,0] and empty array and [5,0] nil?

Leam
--
Mind on a Mission

--
George Drummond
Software Engineer

+44 (0)333 240 2222

[image: Rentify]
6-8 Long Lane, London EC1A 9HF
www.rentify.com

Specifically the last line of documentation for this method: "Returns nil if
the index (or starting index) are out of range."

···

On Thu, Nov 13, 2014 at 5:17 PM, George Drummond <drummond@rentify.com> wrote:

You're using the shorthand for "slice" on the array class.

Ruby docs have some more examples that may help you to work out why it
behaves like it does...
Class: Array (Ruby 2.1.4)

On Thu, Nov 13, 2014 at 4:52 PM, leam hall <leamhall@gmail.com> wrote:

Working through the Ruby koans and came up with a question.

With:
  array = [:peanut, :butter, :and, :jelly]

Then this yeilds true:
  assert_equal , array[4,0]

But so does this:
  assert_equal nil, array[5,0]

Why is [4,0] and empty array and [5,0] nil?

Leam
--
Mind on a Mission

--
George Drummond
Software Engineer

+44 (0)333 240 2222

[image: Rentify]
6-8 Long Lane, London EC1A 9HF
www.rentify.com

--
George Drummond
Software Engineer

+44 (0)333 240 2222

[image: Rentify]
6-8 Long Lane, London EC1A 9HF
www.rentify.com

The nil part makes sense. What I don't get is why the first out of range,
"4", didn't also get nil. The indices should be 0..3, right?

···

On Thu, Nov 13, 2014 at 12:18 PM, George Drummond <drummond@rentify.com> wrote:

Specifically the last line of documentation for this method: "Returns nil if
the index (or starting index) are out of range."

--
Mind on a Mission <http://leamhall.blogspot.com/&gt;

It is kind of strange.

If you look at the examples section there is a "special cases" list and
your example appears there.

I don't know the reasons for this.

···

On Thu, Nov 13, 2014 at 5:32 PM, leam hall <leamhall@gmail.com> wrote:

On Thu, Nov 13, 2014 at 12:18 PM, George Drummond <drummond@rentify.com> > wrote:

Specifically the last line of documentation for this method: "Returns nil if
the index (or starting index) are out of range."

The nil part makes sense. What I don't get is why the first out of range,
"4", didn't also get nil. The indices should be 0..3, right?

--
Mind on a Mission <http://leamhall.blogspot.com/&gt;

--
George Drummond
Software Engineer

+44 (0)333 240 2222

[image: Rentify]
6-8 Long Lane, London EC1A 9HF
www.rentify.com

It is kind of strange.

If you look at the examples section there is a "special cases" list and your example appears there.

I don't know the reasons for this.

Here's how *I* think about it:

    [ :a, :b, :c, ]
^ ^ ^ ^ ^ ^
     0 1 2 3 4
-4 -3 -2 -1

If the index "points" to positions "between" the actual elements, then you can treat the index 3 (in this case) as still being "inside" the Array brackets, but 4 is outside. If a slice starts "inside" the Array, it returns an Array, but if you completely "miss" the Array, you get nil.

example = [ :a, :b, :c, ]
(-4..4).each do |i|
  puts "example[#{i}] \t\#=> #{example[i].inspect}"
  puts "example[#{i},2]\t\#=> #{example[i,2].inspect}"
end

example[-4] #=> nil
example[-4,2] #=> nil
example[-3] #=> :a
example[-3,2] #=> [:a, :b]
example[-2] #=> :b
example[-2,2] #=> [:b, :c]
example[-1] #=> :c
example[-1,2] #=> [:c]
example[0] #=> :a
example[0,2] #=> [:a, :b]
example[1] #=> :b
example[1,2] #=> [:b, :c]
example[2] #=> :c
example[2,2] #=> [:c]
example[3] #=> nil
example[3,2] #=>
example[4] #=> nil
example[4,2] #=> nil

Note that [2,2] can't actually give 2 elements because the Array is exhausted, but it returns what it can. [3,2] is similar: it runs out of elements before it find even one, but it starts "inside" so it gives an Array in return.

-Rob

···

On 2014-Nov-13, at 12:39 , George Drummond <drummond@rentify.com> wrote:

On Thu, Nov 13, 2014 at 5:32 PM, leam hall <leamhall@gmail.com> wrote:

On Thu, Nov 13, 2014 at 12:18 PM, George Drummond <drummond@rentify.com> wrote:
Specifically the last line of documentation for this method: "Returns nil if the index (or starting index) are out of range."

The nil part makes sense. What I don't get is why the first out of range, "4", didn't also get nil. The indices should be 0..3, right?

--
Mind on a Mission

--
George Drummond
Software Engineer

+44 (0)333 240 2222

6-8 Long Lane, London EC1A 9HF
www.rentify.com

I believe I've tracked it down.

See this:
https://www.omniref.com/ruby/2.1.2/symbols/Array/[]#line=1261

which calls rb_ary_subseq
  http://rxr.whitequark.org/mri/source/array.c#1126

1. In the case where you passed in 5, it's larger than the length of the
array, so you get nil.

2. In the case where you passed in 4, it's the same as the length of the
array. You passed in zero (0) as the 2nd param, which maps to "len" in the
C code.

It goes to this line: http://rxr.whitequark.org/mri/source/array.c#1137

   if (len <http://rxr.whitequark.org/mri/ident?i=len&gt; == 0) return
ary_new <http://rxr.whitequark.org/mri/ident?i=ary_new&gt;\(klass
<http://rxr.whitequark.org/mri/ident?i=klass&gt;, 0);

Then it goes here: http://rxr.whitequark.org/mri/source/array.c#399
    ary_new <http://rxr.whitequark.org/mri/ident?i=ary_new&gt;\(VALUE
<http://rxr.whitequark.org/mri/ident?i=VALUE&gt; klass
<http://rxr.whitequark.org/mri/ident?i=klass&gt;, long capa
<http://rxr.whitequark.org/mri/ident?i=capa&gt; )

And then this line: http://rxr.whitequark.org/mri/source/array.c#423
ary <http://rxr.whitequark.org/mri/ident?i=ary&gt; = ary_alloc
<http://rxr.whitequark.org/mri/ident?i=ary_alloc&gt;\(klass
<http://rxr.whitequark.org/mri/ident?i=klass&gt;\);

which is why you get an array of zero elements.

···

On Thu, Nov 13, 2014 at 1:42 PM, Rob Biedenharn <rob.biedenharn@gmail.com> wrote:

On 2014-Nov-13, at 12:39 , George Drummond <drummond@rentify.com> wrote:

It is kind of strange.

If you look at the examples section there is a "special cases" list and
your example appears there.

I don't know the reasons for this.

Here's how *I* think about it:

    [ :a, :b, :c, ]
^ ^ ^ ^ ^ ^
     0 1 2 3 4
-4 -3 -2 -1

If the index "points" to positions "between" the actual elements, then you
can treat the index 3 (in this case) as still being "inside" the Array
brackets, but 4 is outside. If a slice starts "inside" the Array, it
returns an Array, but if you completely "miss" the Array, you get nil.

example = [ :a, :b, :c, ]
(-4..4).each do |i|
  puts "example[#{i}] \t\#=> #{example[i].inspect}"
  puts "example[#{i},2]\t\#=> #{example[i,2].inspect}"
end

example[-4] #=> nil
example[-4,2] #=> nil
example[-3] #=> :a
example[-3,2] #=> [:a, :b]
example[-2] #=> :b
example[-2,2] #=> [:b, :c]
example[-1] #=> :c
example[-1,2] #=> [:c]
example[0] #=> :a
example[0,2] #=> [:a, :b]
example[1] #=> :b
example[1,2] #=> [:b, :c]
example[2] #=> :c
example[2,2] #=> [:c]
example[3] #=> nil
example[3,2] #=>
example[4] #=> nil
example[4,2] #=> nil

Note that [2,2] can't actually give 2 elements because the Array is
exhausted, but it returns what it can. [3,2] is similar: it runs out of
elements before it find even one, but it starts "inside" so it gives an
Array in return.

-Rob

On Thu, Nov 13, 2014 at 5:32 PM, leam hall <leamhall@gmail.com> wrote:

On Thu, Nov 13, 2014 at 12:18 PM, George Drummond <drummond@rentify.com> >> wrote:

Specifically the last line of documentation for this method: "Returns
nil if the index (or starting index) are out of range."

The nil part makes sense. What I don't get is why the first out of range,
"4", didn't also get nil. The indices should be 0..3, right?

--
Mind on a Mission <http://leamhall.blogspot.com/&gt;

--
George Drummond
Software Engineer

+44 (0)333 240 2222

[image: Rentify]
6-8 Long Lane, London EC1A 9HF
www.rentify.com

Ken, that's a lot of tracking, cool!

Does it make sense to use the array length as the highest index possible before returning a nil value?

Leam

···

On 11/13/14 15:18, Ken Chien wrote:

I believe I've tracked it down.

See this:
https://www.omniref.com/ruby/2.1.2/symbols/Array/[]#line=1261

which calls rb_ary_subseq
http://rxr.whitequark.org/mri/source/array.c#1126

1. In the case where you passed in 5, it's larger than the length of the
array, so you get nil.

2. In the case where you passed in 4, it's the same as the length of the
array. You passed in zero (0) as the 2nd param, which maps to "len" in
the C code.

It goes to this line: http://rxr.whitequark.org/mri/source/array.c#1137

    if (len <http://rxr.whitequark.org/mri/ident?i=len&gt; == 0)return ary_new <http://rxr.whitequark.org/mri/ident?i=ary_new&gt;\(klass <http://rxr.whitequark.org/mri/ident?i=klass&gt;, 0);

Then it goes here: http://rxr.whitequark.org/mri/source/array.c#399
ary_new <http://rxr.whitequark.org/mri/ident?i=ary_new&gt;\(VALUE
<http://rxr.whitequark.org/mri/ident?i=VALUE&gt; klass
<http://rxr.whitequark.org/mri/ident?i=klass&gt;, long capa
<http://rxr.whitequark.org/mri/ident?i=capa&gt; )

And then this line:http://rxr.whitequark.org/mri/source/array.c#423
ary <http://rxr.whitequark.org/mri/ident?i=ary&gt; =ary_alloc <http://rxr.whitequark.org/mri/ident?i=ary_alloc&gt;\(klass <http://rxr.whitequark.org/mri/ident?i=klass&gt;\);

which is why you get an array of zero elements.

On Thu, Nov 13, 2014 at 1:42 PM, Rob Biedenharn > <rob.biedenharn@gmail.com <mailto:rob.biedenharn@gmail.com>> wrote:

    On 2014-Nov-13, at 12:39 , George Drummond <drummond@rentify.com > <mailto:drummond@rentify.com>> wrote:

    It is kind of strange.

    If you look at the examples section there is a "special cases"
    list and your example appears there.

    I don't know the reasons for this.

    Here's how *I* think about it:

         [ :a, :b, :c, ]
      ^ ^ ^ ^ ^ ^
          0 1 2 3 4
      -4 -3 -2 -1

    If the index "points" to positions "between" the actual elements,
    then you can treat the index 3 (in this case) as still being
    "inside" the Array brackets, but 4 is outside. If a slice starts
    "inside" the Array, it returns an Array, but if you completely
    "miss" the Array, you get nil.

    example = [ :a, :b, :c, ]
    (-4..4).each do |i|
       puts "example[#{i}] \t\#=> #{example[i].inspect}"
       puts "example[#{i},2]\t\#=> #{example[i,2].inspect}"
    end

    example[-4] #=> nil
    example[-4,2]#=> nil
    example[-3] #=> :a
    example[-3,2]#=> [:a, :b]
    example[-2] #=> :b
    example[-2,2]#=> [:b, :c]
    example[-1] #=> :c
    example[-1,2]#=> [:c]
    example[0] #=> :a
    example[0,2]#=> [:a, :b]
    example[1] #=> :b
    example[1,2]#=> [:b, :c]
    example[2] #=> :c
    example[2,2]#=> [:c]
    example[3] #=> nil
    example[3,2]#=>
    example[4] #=> nil
    example[4,2]#=> nil

    Note that [2,2] can't actually give 2 elements because the Array is
    exhausted, but it returns what it can. [3,2] is similar: it runs out
    of elements before it find even one, but it starts "inside" so it
    gives an Array in return.

    -Rob

    On Thu, Nov 13, 2014 at 5:32 PM, leam hall <leamhall@gmail.com >> <mailto:leamhall@gmail.com>> wrote:

        On Thu, Nov 13, 2014 at 12:18 PM, George Drummond >> <drummond@rentify.com <mailto:drummond@rentify.com>> wrote:

            Specifically the last line of documentation for this
            method: "Returns |nil| if the index (or starting index)
            are out of range."

        The nil part makes sense. What I don't get is why the first
        out of range, "4", didn't also get nil. The indices should be
        0..3, right?

        --
        Mind on a Mission <http://leamhall.blogspot.com/&gt;

    --
    George Drummond
    Software Engineer

    +44 (0)333 240 2222 <tel:%2B44%20%280%29333%20240%202222>

    Rentify
    6-8 Long Lane, London EC1A 9HF
    www.rentify.com <https://www.rentify.com/&gt;

--
http://31challenge.net
http://31challenge.net/insight