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

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 [email protected] wrote:

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

Leam

Mind on a Mission


George D.
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 D. [email protected]
wrote:

With:
Leam
+44 (0)333 240 2222

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


George D.
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.

On Thu, Nov 13, 2014 at 5:32 PM, leam hall [email protected] wrote:


Mind on a Mission http://leamhall.blogspot.com/


George D.
Software Engineer

+44 (0)333 240 2222

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

On Thu, Nov 13, 2014 at 12:18 PM, George D. [email protected]
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?

On 2014-Nov-13, at 12:39 , George D. [email protected] 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

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 == 0) return
ary_new http://rxr.whitequark.org/mri/ident?i=ary_new(klass
http://rxr.whitequark.org/mri/ident?i=klass, 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(VALUE
http://rxr.whitequark.org/mri/ident?i=VALUE klass
http://rxr.whitequark.org/mri/ident?i=klass, long capa
http://rxr.whitequark.org/mri/ident?i=capa )

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

which is why you get an array of zero elements.

On Thu, Nov 13, 2014 at 1:42 PM, Rob B.
[email protected]

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