LaunchKit
All quizzes
Ruby 1 views

Chained [0][0][0][1] ends inside a String

Question

What is the return value of the following Ruby code?

words = [["abc", ["def"]], "ghi"]

words[0][0][0][1] # => ???

The correct answer is

Explanation

TL;DR

Each [...] applies to the result of the previous one, and the chain changes type midway. words[0] is an Array, but words[0][0] is the String "abc". From there String#[] takes over: "abc"[0] is "a", and "a"[1] asks for the second character of a one-character string, which is nil.

Step by step

words = [["abc", ["def"]], "ghi"]

words[0]          # => ["abc", ["def"]]
words[0][0]       # => "abc"
words[0][0][0]    # => "a"
words[0][0][0][1] # => nil

The trap is the silent switch of receiver class. The first two [] are Array#[]; the last two are String#[], which indexes characters and returns one-character strings:

"abc"[0] # => "a"
"abc"[1] # => "b"
"abc"[3] # => nil

The distractor answers correspond to different chains:

words = [["abc", ["def"]], "ghi"]

words[1]    # => "ghi"
words[0][1] # => ["def"]

And "b" would require indexing "abc"[1], not "abc"[0][1].

Edge cases

Out-of-range indexing returns nil for both arrays and strings, with one classic exception: a range that starts exactly at the end returns an empty slice:

"abc"[3]   # => nil
"abc"[3..] # => ""
"abc"[4..] # => nil

[1, 2, 3][3]   # => nil
[1, 2, 3][3..] # => []

Array#dig walks nested collections, but it does not silently cross into strings; it raises instead, which turns a wrong assumption about the nesting into a loud error:

words = [["abc", ["def"]], "ghi"]

words.dig(0, 0)    # => "abc"
words.dig(0, 1, 0) # => "def"

begin
  words.dig(0, 0, 0, 1)
rescue TypeError => e
  e.message # => "String does not have #dig method"
end

Version notes

In Ruby 1.8, "abc"[0] returned the character code 97. Since Ruby 1.9, String#[] with an Integer index returns a one-character string, which is what makes this chain produce "a" and then nil.

Share this quiz

Comments

No comments yet. Be the first.

Only used to confirm and publish your comment. Never shown publicly, never shared.

Markdown: **bold**, `code`, ```fenced blocks```, > quotes, [links](url). HTML and images are not rendered.